Persist Redis (AOF+vol), read config from mounted secrets.js, add backup/restore docs (#118)
Lossless upgrades + config story for the all-in-one proxy image. Redis persistence (Part A): - Replace in-memory `--save "" --appendonly no` with AOF + RDB persisted to /data. Host records, permissions, DNS creds, local users, AND the lua-resty-auto-ssl Let's Encrypt certs now all survive container recreation (persisting Redis persists the cert store — no LE re-issue / rate-limit on rebuild). - Add the `proxy-data` named volume -> /data in docker-compose.yml; fix the stale "in-memory, lost on recreation" comment. Config from ./config/proxy-secrets.js (Part B): - docker-entrypoint.sh: when /config/proxy-secrets.js is mounted, symlink it to /app/conf/secrets.js so @simpleworkjs/conf reads the oidc/ldap/auth config from the file. No app_* env should then be passed (app_* beats secrets.js). Falls back to app_* env when the file is absent (standalone still works). - docker-compose.yml: drop all app_oidc__* / app_ldap__* / app_auth__* env and add `./config:/config:ro`. Keep RESOLVER/REAL_IP_FROM/NODE_ENV/NODE_PORT (OpenResty-runtime / process env, not app_* config). No env_file. - New secrets.js.example (the proxy had none): oidc (enabled, endpoints, clientId/clientSecret, redirectUri, scopes, claims), ldap (url, bindDN, bindPassword, searchBase, userFilter, tlsOptions), auth (adminGroups, adminUsers, groupRoleMap), plus an orchestrator-only `stack` key. Backup/restore docs: - Full "Backups and restore" runbook in DEPLOYMENT.md (what lives where, manual backup, Redis restore with the AOF-vs-RDB note — AOF wins on startup so the AOF must be deleted before an RDB load; restoring Redis restores cert state at snapshot time; migrations note). Update the Setup + Auto-SSL sections. - docs/docker.md: update Quick start + How configuration works + Auto-SSL for the new ./config/ approach (app_* env now advanced/optional). Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
'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 symlinks
|
||||
// it into /app/conf/secrets.js 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: copy to nodejs/conf/secrets.js and fill in your values. 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 = {
|
||||
// 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',
|
||||
},
|
||||
|
||||
// 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: {},
|
||||
},
|
||||
|
||||
// ── 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
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user