setup.sh: take a plain domain (CFG_DOMAIN), derive the LDAP base DN (#18)
Entering the base DN directly (CFG_BASE_DN=dc=foo,dc=bar) is fragile — a missing comma between labels silently produces a malformed domain (e.g. "theta42dc=duckdns.org" instead of "theta42.duckdns.org") with no validation to catch it. Flip the direction: operators now set CFG_DOMAIN to a plain domain (any number of labels — a DuckDNS domain like foo.duckdns.org works the same as a normal one), and setup.sh derives the base DN from it via the new dn_from_domain(). CFG_BASE_DN is still supported as an explicit override (e.g. to namespace under an OU-style prefix) and is how migrated .env/proxy.env deployments keep working, since domain_from_dn() still reads the domain back out of an existing DN either way.
This commit is contained in:
@@ -64,10 +64,10 @@ real TLS certificates for it via Let's Encrypt. A `.local` or made-up name only
|
||||
gets you a self-signed cert (browsers will warn — fine for testing, painful for
|
||||
daily use).
|
||||
|
||||
The domain is the **one** value you set in `setup.env` (as the LDAP base DN,
|
||||
e.g. `CFG_BASE_DN=dc=lab,dc=example,dc=com` for `lab.example.com`) — see
|
||||
*Quickstart*. The SSO/proxy hostnames default to `sso.<domain>` /
|
||||
`proxy.<domain>`, derived from it.
|
||||
The domain is the **one** value you set in `setup.env` (e.g.
|
||||
`CFG_DOMAIN=lab.example.com`) — see *Quickstart*. The SSO/proxy hostnames
|
||||
default to `sso.<domain>` / `proxy.<domain>`, and the LDAP base DN
|
||||
(`dc=lab,dc=example,dc=com`) is built from it automatically.
|
||||
|
||||
### 2. At least two hostnames, pointing at your public IP
|
||||
|
||||
@@ -123,12 +123,13 @@ standalone (`docker-compose`) both work.
|
||||
```bash
|
||||
git clone --recursive https://github.com/theta42/theta-env.git
|
||||
cd theta-env
|
||||
cp setup.env.example setup.env # then edit setup.env: set CFG_BASE_DN to your domain
|
||||
cp setup.env.example setup.env # then edit setup.env: set CFG_DOMAIN to your domain
|
||||
./setup.sh # first run: generates ./config/ from setup.env, builds + bootstraps + starts
|
||||
```
|
||||
|
||||
Your domain is entered **once**, as the LDAP base DN in `setup.env` (e.g.
|
||||
`CFG_BASE_DN=dc=lab,dc=example,dc=com` for the domain `lab.example.com`). The
|
||||
Your domain is entered **once** in `setup.env` (e.g.
|
||||
`CFG_DOMAIN=lab.example.com`) — the LDAP base DN (`dc=lab,dc=example,dc=com`)
|
||||
is derived from it, however many labels it has. The
|
||||
first `./setup.sh` reads `setup.env` and generates `./config/sso-secrets.js` +
|
||||
`./config/proxy-secrets.js` with that domain filled in everywhere (hostnames
|
||||
default to `sso.<domain>` / `proxy.<domain>`) plus random secrets, then builds
|
||||
@@ -441,7 +442,7 @@ exactly in the bootstrap) so the SSO can verify them on bind.
|
||||
|
||||
```
|
||||
theta-env/
|
||||
├── setup.env.example # first-run config template — cp to setup.env, set CFG_BASE_DN
|
||||
├── setup.env.example # first-run config template — cp to setup.env, set CFG_DOMAIN
|
||||
├── config.example/ # committed annotated config templates (copy to ./config/)
|
||||
├── docker-compose.yml # sso-manager + proxy on one bridge net
|
||||
├── setup.sh # one-command idempotent bring-up (manages ./config/ + backups)
|
||||
|
||||
+8
-5
@@ -42,20 +42,23 @@ git submodule update --init --recursive
|
||||
|
||||
```bash
|
||||
cp setup.env.example setup.env
|
||||
$EDITOR setup.env # set CFG_BASE_DN to your domain, as a base DN
|
||||
$EDITOR setup.env # set CFG_DOMAIN to your domain
|
||||
```
|
||||
|
||||
Your domain is entered **once**, as the LDAP base DN. The SSO/proxy hostnames
|
||||
default to `sso.<domain>` / `proxy.<domain>`, derived from it, so for most setups
|
||||
`CFG_BASE_DN` is the only value you set:
|
||||
Your domain is entered **once**, as a plain DNS domain. The SSO/proxy
|
||||
hostnames default to `sso.<domain>` / `proxy.<domain>`, and the LDAP base DN
|
||||
is built from it (any number of labels works — a domain like
|
||||
`myhost.duckdns.org` becomes `dc=myhost,dc=duckdns,dc=org`), so for most
|
||||
setups `CFG_DOMAIN` is the only value you set:
|
||||
|
||||
| `setup.env` key | Example | Notes |
|
||||
|-----|---------|-------|
|
||||
| `CFG_BASE_DN` | `dc=lab,dc=local` | your directory base — **required** |
|
||||
| `CFG_DOMAIN` | `lab.local` | your domain — **required** |
|
||||
| `CFG_SSO_HOST` | `sso.lab.local` | optional, defaults to `sso.<domain>` |
|
||||
| `CFG_PROXY_HOST` | `proxy.lab.local` | optional, defaults to `proxy.<domain>` |
|
||||
| `CFG_ADMIN_UID` | `admin` | optional, defaults to `admin` |
|
||||
| `CFG_ADMIN_EMAIL` | `admin@<proxyHost>` | optional |
|
||||
| `CFG_BASE_DN` | `dc=lab,dc=local` | advanced: override the derived LDAP base DN |
|
||||
|
||||
`setup.env` is used **only on the first run** to generate `./config/`; after
|
||||
that `./config/*.js` are operator-owned and `setup.env` is ignored. Secrets
|
||||
|
||||
+13
-7
@@ -7,24 +7,30 @@
|
||||
# (edit them directly; setup.env is ignored on later runs).
|
||||
#
|
||||
# cp setup.env.example setup.env
|
||||
# $EDITOR setup.env # set CFG_BASE_DN below to your domain
|
||||
# $EDITOR setup.env # set CFG_DOMAIN below to your domain
|
||||
# ./setup.sh # generates ./config/ and builds the stack
|
||||
#
|
||||
# Copying this file to setup.env (gitignored) keeps your domain out of git.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
# Your domain, as an LDAP base DN. THIS IS THE ONE PLACE THE DOMAIN IS ENTERED.
|
||||
# Everything else derives from it: the SSO/proxy hostnames default to
|
||||
# sso.<domain> / proxy.<domain>, and the LDAP DNs are cn=admin,<dn>,
|
||||
# ou=people,<dn>, ou=groups,<dn>. Required — setup.sh refuses to run without it.
|
||||
CFG_BASE_DN=dc=example,dc=com
|
||||
# Your domain. THIS IS THE ONE PLACE THE DOMAIN IS ENTERED. Everything else
|
||||
# derives from it: the SSO/proxy hostnames default to sso.<domain> /
|
||||
# proxy.<domain>, and the LDAP base DN is built from it (example.com becomes
|
||||
# dc=example,dc=com; a 3-label domain like myhost.duckdns.org becomes
|
||||
# dc=myhost,dc=duckdns,dc=org — any number of labels works). Required —
|
||||
# setup.sh refuses to run without it.
|
||||
CFG_DOMAIN=example.com
|
||||
|
||||
# Public hostnames. Optional — default to sso.<domain> / proxy.<domain> derived
|
||||
# from CFG_BASE_DN above. Uncomment and set only if your hostnames differ
|
||||
# from CFG_DOMAIN above. Uncomment and set only if your hostnames differ
|
||||
# (e.g. a different subdomain, or the domain isn't the bare apex):
|
||||
#CFG_SSO_HOST=sso.example.com
|
||||
#CFG_PROXY_HOST=proxy.example.com
|
||||
|
||||
# Advanced: override the derived LDAP base DN directly (e.g. to namespace
|
||||
# under an OU-style prefix). Leave unset to use the DN built from CFG_DOMAIN:
|
||||
#CFG_BASE_DN=dc=example,dc=com
|
||||
|
||||
# Optional — sensible defaults if left blank:
|
||||
#CFG_ORG=SSO Manager # app display name + outbound email org
|
||||
#CFG_ADMIN_UID=admin # initial SSO admin username
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# theta-env setup — one-command bring-up of the unified SSO Manager + Proxy stack.
|
||||
#
|
||||
# git clone --recursive <theta-env> && cd theta-env
|
||||
# cp setup.env.example setup.env # set CFG_BASE_DN to your domain (once)
|
||||
# cp setup.env.example setup.env # set CFG_DOMAIN to your domain (once)
|
||||
# ./setup.sh # first run: generates ./config/ from setup.env, builds + bootstraps + starts
|
||||
# ./setup.sh # later runs: rebuilds + bootstraps + starts (config left untouched)
|
||||
#
|
||||
@@ -20,9 +20,10 @@
|
||||
# SKIP_SUBMODULE_UPDATE=1.
|
||||
# 2. ensure_config: create ./config/sso-secrets.js + proxy-secrets.js if
|
||||
# missing. On a fresh clone the domain/hosts are read from ./setup.env
|
||||
# (the one place the domain is entered, as the LDAP base DN) and both
|
||||
# files are generated with that domain filled in everywhere + random
|
||||
# secrets, then the run proceeds to build (no edit-and-re-run step). On
|
||||
# (the one place the domain is entered, as a plain DNS domain — the LDAP
|
||||
# base DN is derived from it) and both files are generated with that
|
||||
# domain filled in everywhere + random secrets, then the run proceeds to
|
||||
# build (no edit-and-re-run step). On
|
||||
# an existing deployment with .env/proxy.env, the secrets are migrated
|
||||
# (preserved) into ./config. If ./config already exists it is left
|
||||
# untouched (the operator owns it; setup.env is ignored).
|
||||
@@ -125,11 +126,22 @@ fi
|
||||
|| die "proxy/Dockerfile missing. Run: git submodule update --init --recursive"
|
||||
|
||||
# ── 2. ensure_config ──────────────────────────────────────────────────────────
|
||||
# Derive a DNS domain from a base DN (dc=foo,dc=bar -> foo.bar).
|
||||
# Derive a DNS domain from a base DN (dc=foo,dc=bar -> foo.bar). Only used to
|
||||
# read domain back out of a base DN set directly (advanced override, or an
|
||||
# old setup.env / migrated .env) — the normal path is dn_from_domain below.
|
||||
domain_from_dn() {
|
||||
echo "$1" | sed 's/^dc=//; s/,dc=/./g'
|
||||
}
|
||||
|
||||
# Derive an LDAP base DN from a DNS domain (foo.bar -> dc=foo,dc=bar). This is
|
||||
# the normal path: operators enter a plain domain in setup.env (CFG_DOMAIN),
|
||||
# and the base DN is built from it, however many labels it has (a DuckDNS
|
||||
# domain like foo.duckdns.org becomes dc=foo,dc=duckdns,dc=org — LDAP doesn't
|
||||
# care how many dc= components there are).
|
||||
dn_from_domain() {
|
||||
echo "dc=$1" | sed 's/\./,dc=/g'
|
||||
}
|
||||
|
||||
# Write ./config/sso-secrets.js from the CFG_* shell vars.
|
||||
write_sso_secrets() {
|
||||
local dn="$CFG_BASE_DN" domain="$CFG_DOMAIN"
|
||||
@@ -237,8 +249,9 @@ ensure_config() {
|
||||
fi
|
||||
|
||||
# First run: read the domain/hosts from ./setup.env — the ONE place the
|
||||
# domain is entered, as the LDAP base DN (e.g. dc=718it,dc=biz). Hostnames
|
||||
# default to sso.<domain> / proxy.<domain>, derived from it. setup.env is
|
||||
# domain is entered (e.g. 718it.biz), as a plain DNS domain; the LDAP base
|
||||
# DN is derived from it (dc=718it,dc=biz). Hostnames default to
|
||||
# sso.<domain> / proxy.<domain>, also derived from it. setup.env is
|
||||
# used ONLY on first run; once ./config/*.js exist they are operator-owned
|
||||
# and setup.env is ignored. Falls back to legacy .env/proxy.env migration
|
||||
# below for existing deployments.
|
||||
@@ -304,11 +317,15 @@ ensure_config() {
|
||||
migrated=1
|
||||
fi
|
||||
|
||||
# Derive everything from the base DN — the one domain value. No example.com
|
||||
# defaults: a blank base DN means first-run setup hasn't been done yet.
|
||||
[[ -n "$CFG_BASE_DN" ]] \
|
||||
|| die "First run: 'cp setup.env.example setup.env', set CFG_BASE_DN to your domain (e.g. dc=718it,dc=biz), then re-run ./setup.sh"
|
||||
CFG_DOMAIN="${CFG_DOMAIN:-$(domain_from_dn "$CFG_BASE_DN")}"
|
||||
# Derive everything from the domain — the one value operators enter. No
|
||||
# example.com defaults: a blank domain means first-run setup hasn't been
|
||||
# done yet. CFG_BASE_DN can still be set directly (setup.env or a migrated
|
||||
# .env) to override the derived DN or to read the domain back out of an
|
||||
# old-style DN-first setup.env; if not, it's built from CFG_DOMAIN.
|
||||
CFG_DOMAIN="${CFG_DOMAIN:-$([[ -n "$CFG_BASE_DN" ]] && domain_from_dn "$CFG_BASE_DN" || true)}"
|
||||
[[ -n "$CFG_DOMAIN" ]] \
|
||||
|| die "First run: 'cp setup.env.example setup.env', set CFG_DOMAIN to your domain (e.g. example.com), then re-run ./setup.sh"
|
||||
CFG_BASE_DN="${CFG_BASE_DN:-$(dn_from_domain "$CFG_DOMAIN")}"
|
||||
CFG_SSO_HOST="${CFG_SSO_HOST:-sso.$CFG_DOMAIN}"
|
||||
CFG_PROXY_HOST="${CFG_PROXY_HOST:-proxy.$CFG_DOMAIN}"
|
||||
CFG_ORG="${CFG_ORG:-SSO Manager}"
|
||||
|
||||
Reference in New Issue
Block a user