1e38ef8dc5
The per-host "Allowed groups" field suggested only local groups, permission subjects and conf.auth maps. None of those can ever match an SSO-gated host: its allow-list is checked against the `groups` claim the SSO issues (utils/host_sso.js), so only SSO groups are candidates. Adds a conf.sso block (url + read-only apiToken, minted by theta-suite's bootstrap) and a cached /api/group lookup merged into the suggestions. Degrades silently to the previous local-only list when unset, and never fails the request. Authenticates with `Authorization: Bearer <token>` -- the SSO's `auth-token` header is for browser session UUIDs and rejects a minted API token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
100 lines
4.8 KiB
Plaintext
100 lines
4.8 KiB
Plaintext
'use strict';
|
|
|
|
// Example secrets configuration for the theta42/proxy.
|
|
//
|
|
// The proxy is an OIDC client of an SSO Manager (or any OIDC provider) AND a
|
|
// direct LDAP client for user lookups. This file supplies that wiring.
|
|
//
|
|
// Docker / unified stack: place at ./config/proxy-secrets.js and bind-mount
|
|
// ./config at /config (see docker-compose.yml); docker-entrypoint.sh points the
|
|
// CONF_SECRETS env var at it so @simpleworkjs/conf reads it. No app_* env
|
|
// should be passed — app_* env beats this file in @simpleworkjs/conf, so the
|
|
// file is authoritative only if the matching app_* env is absent.
|
|
//
|
|
// Bare-metal: ops/install.sh seeds this file at /etc/proxy/secrets.js on first
|
|
// run (with placeholders for the values it can't guess) and points the
|
|
// systemd unit's CONF_SECRETS env var at it. Fill in your values, then
|
|
// `sudo systemctl restart proxy`. Values here override conf/base.js and win
|
|
// over <environment>.js.
|
|
//
|
|
// Only the keys the app reads are listed below. The `stack` key is read by the
|
|
// theta-env orchestrator (setup.sh) and ignored by the app.
|
|
|
|
module.exports = {
|
|
name: 'Dynamic Proxy', // shown in the UI
|
|
logo: '/static/img/theta42.svg', // nav image; point at your own file under public/ to white-label
|
|
|
|
// OpenID Connect — point at your SSO Manager. Issuer + authorization/
|
|
// endSession are browser-facing URLs; token/userinfo can be the internal
|
|
// URL if the SSO is on the same docker network (avoids a TLS hairpin).
|
|
oidc: {
|
|
enabled: true,
|
|
issuer: 'https://sso.example.com',
|
|
authorizationEndpoint: 'https://sso.example.com/oauth/authorize',
|
|
tokenEndpoint: 'http://sso-manager:3001/oauth/token',
|
|
userinfoEndpoint: 'http://sso-manager:3001/oauth/userinfo',
|
|
endSessionEndpoint: 'https://sso.example.com/oauth/logout',
|
|
clientId: 'set-me', // registered on the SSO
|
|
clientSecret: 'set-me', // from the SSO client record
|
|
redirectUri: 'https://proxy.example.com/api/auth/oidc/callback',
|
|
scopes: ['openid', 'profile', 'email', 'groups'],
|
|
groupsClaim: 'groups',
|
|
usernameClaim: 'preferred_username',
|
|
},
|
|
|
|
// Read-only access to the SSO's management API, used to populate the
|
|
// per-host SSO allow-list autocomplete with the directory's actual groups.
|
|
// A host gated on SSO matches its allow-list against the `groups` claim the
|
|
// SSO issues, so only SSO groups can ever match -- without this the field
|
|
// can only suggest the proxy's own local groups. `apiToken` is a machine
|
|
// token minted by theta-suite's bootstrap; leaving it blank simply falls
|
|
// back to local-only suggestions.
|
|
sso: {
|
|
url: 'http://sso-manager:3001',
|
|
apiToken: '',
|
|
},
|
|
|
|
// Direct LDAP user lookups. ldaps:// + rejectUnauthorized:false for a
|
|
// self-signed cert (the SSO's default), or set tlsOptions.ca to a CA path
|
|
// for strict verification. bindPassword MUST match the
|
|
// serviceAccountPass in the SSO's sso-secrets.js (the proxy binds as that
|
|
// service account).
|
|
ldap: {
|
|
url: 'ldaps://sso-manager:636',
|
|
bindDN: 'cn=ldapclient,ou=people,dc=example,dc=com',
|
|
bindPassword: 'set-me',
|
|
searchBase: 'ou=people,dc=example,dc=com',
|
|
userFilter: '(objectClass=inetOrgPerson)',
|
|
userNameAttribute: 'uid',
|
|
tlsOptions: {
|
|
rejectUnauthorized: false, // true + ca for a CA-signed cert
|
|
},
|
|
},
|
|
|
|
// Authorization. adminUsers is the local anti-lockout admin (matches
|
|
// auth.adminUsers in conf/base.js). adminGroups: SSO/LDAP groups whose
|
|
// members are always global admins.
|
|
auth: {
|
|
adminGroups: [],
|
|
adminUsers: ['proxyadmin'],
|
|
groupRoleMap: {},
|
|
// Optional: the local anti-lockout admin's initial password, used
|
|
// ONLY the first time that account is created. Leave unset and a
|
|
// random password is generated and printed to the container log on
|
|
// first boot — fine for a quick local test if you copy it from the
|
|
// log right away, but set this (or change the password afterward)
|
|
// before exposing the proxy publicly. Once the account exists, this
|
|
// key is never read again; change the password via the app itself
|
|
// (or delete the Redis user to force it to be re-bootstrapped with a
|
|
// new value here).
|
|
// localAdminPass: 'change-me',
|
|
},
|
|
|
|
// ── Orchestrator-only (ignored by the app) ───────────────────────────────
|
|
// Read by the theta-env setup.sh (e.g. to seed the OAuth client). Omit for
|
|
// bare-metal use.
|
|
stack: {
|
|
ssoHost: 'sso.example.com', // public SSO hostname
|
|
proxyHost: 'proxy.example.com', // public proxy hostname
|
|
},
|
|
}; |