feat(services): multi-domain routing, split-horizon and OIDC hardening
Bundle of cross-role changes for the gymb services deployment: - Traefik routers: OR-combine opnform/homarr/bookstack Host rules with new *_extra_domains (internal *.int.* FQDNs for a DMZ reverseproxy), and emit tls.certresolver only when traefik_cert_mode == acme (drawio, homarr, opnform, send). - Split-horizon: bookstack_extra_hosts / opnform_extra_hosts add container /etc/hosts overrides so containers reach the IdP public FQDN over the LAN. - bookstack: assert the OIDC issuer resolves concretely (reject "//v2.0"), allowing non-Entra IdPs that override bookstack_oidc_issuer. - homarr: derive the bcrypt salt from the password digest so the admin hash is idempotent — no spurious template changes / container restarts. - opnform: PATCH an existing OIDC connection instead of skipping (applies corrected inventory on re-run); add OIDC_FORCE_LOGIN (enabled only after bootstrap) and an optional direct-SSO ingress entrypoint. Docs: READMEs and meta/argument_specs.yml updated for all new variables.
This commit is contained in:
parent
bb64ccf71e
commit
518d80ec71
17 changed files with 309 additions and 37 deletions
|
|
@ -6,6 +6,12 @@ services:
|
|||
image: {{ opnform_api_image }}
|
||||
container_name: opnform-api
|
||||
restart: unless-stopped
|
||||
{% if opnform_extra_hosts | length > 0 %}
|
||||
extra_hosts:
|
||||
{% for host in opnform_extra_hosts %}
|
||||
- "{{ host }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
volumes:
|
||||
- {{ opnform_storage_dir }}:/usr/share/nginx/html/storage:rw
|
||||
environment: &api-env
|
||||
|
|
@ -14,6 +20,9 @@ services:
|
|||
APP_URL: "{{ opnform_base_url }}"
|
||||
APP_DEBUG: "false"
|
||||
SELF_HOSTED: "true"
|
||||
{% if opnform_oidc_enabled and (_opnform_force_login_effective | default(false)) %}
|
||||
OIDC_FORCE_LOGIN: "true"
|
||||
{% endif %}
|
||||
|
||||
LOG_CHANNEL: errorlog
|
||||
LOG_LEVEL: info
|
||||
|
|
@ -173,10 +182,13 @@ services:
|
|||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network={{ opnform_traefik_network }}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.rule=Host(`{{ opnform_domain }}`)
|
||||
- traefik.http.routers.{{ opnform_service_name }}.rule={% set _all_domains = [opnform_domain] + (opnform_extra_domains | default([])) %}{% for d in _all_domains %}Host(`{{ d }}`){% if not loop.last %} || {% endif %}{% endfor +%}
|
||||
{% if opnform_use_ssl %}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.entrypoints=websecure
|
||||
- traefik.http.routers.{{ opnform_service_name }}.tls=true
|
||||
{% if traefik_cert_mode | default('selfsigned') == 'acme' %}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.tls.certresolver={{ traefik_ssl_cert_resolver | default('dns') }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.entrypoints=web
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,17 @@ server {
|
|||
|
||||
index index.html index.htm index.php;
|
||||
|
||||
{% if opnform_oidc_enabled and opnform_oidc_sso_entrypoint %}
|
||||
# Direct-SSO entrypoint: a tiny page that asks the API for the IdP
|
||||
# authorize URL (no email/domain check on this endpoint) and forwards
|
||||
# the browser there. Link users here instead of /login to skip the
|
||||
# email field entirely. Exact-match so it wins over the `/` prefix.
|
||||
location = {{ opnform_oidc_sso_path }} {
|
||||
default_type text/html;
|
||||
return 200 '<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Redirecting to sign-in…</title></head><body style="font-family:sans-serif;text-align:center;padding:3rem;color:#374151"><p id="m">Redirecting to sign-in…</p><script>fetch("/api/auth/{{ opnform_oidc_slug }}/redirect",{method:"POST",headers:{Accept:"application/json"}}).then(function(r){if(!r.ok)throw new Error("HTTP "+r.status);return r.json()}).then(function(d){if(d&&d.redirect_url){window.location.replace(d.redirect_url)}else{throw new Error("no redirect_url")}}).catch(function(e){document.getElementById("m").textContent="Sign-in redirect failed: "+e.message+". Go to the login page instead.";var a=document.createElement("a");a.href="/login";a.textContent="Open login page";a.style.display="block";a.style.marginTop="1rem";document.body.appendChild(a)});</script></body></html>';
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass http://ui:3000;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue