From 4444d1b9e45e3c8d14258a0eab9b867b7992365c Mon Sep 17 00:00:00 2001 From: Robert Gingras Date: Thu, 4 Jun 2026 09:27:36 -0400 Subject: [PATCH 1/6] feat: use a template for sssd configuration --- images/base/50-sssd-conf-template.conf | 3 +++ images/base/Dockerfile | 3 ++- images/base/sssd.conf | 15 --------------- images/base/sssd.conf.template | 24 ++++++++++++++++++++++++ 4 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 images/base/50-sssd-conf-template.conf delete mode 100644 images/base/sssd.conf create mode 100644 images/base/sssd.conf.template diff --git a/images/base/50-sssd-conf-template.conf b/images/base/50-sssd-conf-template.conf new file mode 100644 index 00000000..a8ec0fb1 --- /dev/null +++ b/images/base/50-sssd-conf-template.conf @@ -0,0 +1,3 @@ +[Service] +EnvironmentFile=-/etc/environment +ExecStartPre=+-/bin/sh -cstorage/bin/envsubst /etc/sssd/sssd.conf" diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 81f2b560..249f83a2 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -23,7 +23,8 @@ RUN apt-get update && \ pam-auth-update --enable mkhomedir && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -COPY --chmod=0440 sssd.conf /etc/sssd/sssd.conf +COPY --chmod=0440 sssd.conf.template /etc/sssd/sssd.conf.template +COPY --chmod=0440 50-sssd-conf-template.conf /etc/systemd/system/sssd.service.d/50-sssd-conf-template.conf COPY --chmod=0440 ldapusers /etc/sudoers.d/ldapusers COPY --chmod=0644 ldap.conf /etc/ldap/ldap.conf COPY --chmod=0755 git-identity.sh /etc/profile.d/git-identity.sh diff --git a/images/base/sssd.conf b/images/base/sssd.conf deleted file mode 100644 index 73d486cf..00000000 --- a/images/base/sssd.conf +++ /dev/null @@ -1,15 +0,0 @@ -[sssd] -domains = default - -[domain/default] -id_provider = ldap -auth_provider = ldap -ldap_uri = ldaps://ldap1:636, ldaps://ldap2:636 -ldap_tls_reqcert = allow - -# Map LDAP cn attribute to the NSS gecos field so that tools like getent, -# finger, and the git-identity profile script can read the user's full name. -ldap_user_gecos = cn - -# set a timeout long enough for a push notification to be responded to -ldap_opt_timeout = 60 diff --git a/images/base/sssd.conf.template b/images/base/sssd.conf.template new file mode 100644 index 00000000..f889f46e --- /dev/null +++ b/images/base/sssd.conf.template @@ -0,0 +1,24 @@ +[sssd] +domains = default + +[domain/default] +id_provider = ldap +auth_provider = ldap +ldap_uri = ${SSSD_LDAP_URI} +ldap_tls_reqcert = ${SSSD_LDAP_TLS_REQCERT} + +ldap_schema = ${SSSD_LDAP_SCHEMA} +ldap_search_base = ${SSSD_LDAP_SEARCH_BASE} +ldap_user_search_base = ${SSSD_LDAP_USER_SEARCH_BASE} +ldap_group_search_base = ${SSSD_LDAP_GROUP_SEARCH_BASE} + +# Map LDAP cn attribute to the NSS gecos field so that tools like getent, +# finger, and the git-identity profile script can read the user's full name. +ldap_user_gecos = cn + +ldap_default_bind_dn = ${SSSD_LDAP_DEFAULT_BIND_DN} +ldap_default_authtok_type = ${SSSD_DEFAULT_AUTHTOK_TYPE} +ldap_default_authtok = ${SSSD_DEFAULT_AUTHTOK} + +# set a timeout long enough for a push notification to be responded to +ldap_opt_timeout = 60 From 414101c5d52f3faee1182c3654222bced0703adf Mon Sep 17 00:00:00 2001 From: Robert Gingras Date: Thu, 4 Jun 2026 09:36:22 -0400 Subject: [PATCH 2/6] refactor: improve logging and add retry to image curl --- images/base/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 249f83a2..6e89cdfe 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -5,7 +5,7 @@ FROM debian:13 AS builder RUN apt-get update && apt-get install -y \ curl tar zstd ARG URL=http://download.proxmox.com/images/system/debian-13-standard_13.1-2_amd64.tar.zst -RUN mkdir /rootfs && curl "$URL" | tar --zstd -x -C /rootfs +RUN mkdir /rootfs && curl -fsSL --retry 10 "$URL" | tar --zstd -x -C /rootfs # Stage 2 of the build uses the root filesystem built in stage 1. The rest of # the Dockerfile builds from there. From 5b1be334a0b3d384eacb7254f90868c38a63db14 Mon Sep 17 00:00:00 2001 From: Robert Gingras Date: Thu, 4 Jun 2026 10:26:28 -0400 Subject: [PATCH 3/6] fix: ensure sssd generates the template with correct permissions --- images/base/50-sssd-conf-template.conf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/images/base/50-sssd-conf-template.conf b/images/base/50-sssd-conf-template.conf index a8ec0fb1..9c617d9c 100644 --- a/images/base/50-sssd-conf-template.conf +++ b/images/base/50-sssd-conf-template.conf @@ -1,3 +1,6 @@ +[Unit] +ConditionPathExists=|/etc/sssd/sssd.conf.template + [Service] EnvironmentFile=-/etc/environment -ExecStartPre=+-/bin/sh -cstorage/bin/envsubst /etc/sssd/sssd.conf" +ExecStartPre=+-/bin/sh -c "umask 0226 && /bin/envsubst /etc/sssd/sssd.conf" From 26e908a6ee066fafa1897220ab7f59eec2b5f881 Mon Sep 17 00:00:00 2001 From: Robert Gingras Date: Thu, 4 Jun 2026 10:41:08 -0400 Subject: [PATCH 4/6] feat: add sssd template setting variables to the admin settings --- .../src/pages/settings/SettingsPage.tsx | 52 ++++++-- .../20260604000000-seed-sssd-env-vars.js | 121 ++++++++++++++++++ 2 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 create-a-container/seeders/20260604000000-seed-sssd-env-vars.js diff --git a/create-a-container/client/src/pages/settings/SettingsPage.tsx b/create-a-container/client/src/pages/settings/SettingsPage.tsx index a99b301b..d862466c 100644 --- a/create-a-container/client/src/pages/settings/SettingsPage.tsx +++ b/create-a-container/client/src/pages/settings/SettingsPage.tsx @@ -11,6 +11,12 @@ import { PageHeader, Spinner, Switch, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, useToast, } from '@mieweb/ui'; import { Plus, Settings as SettingsIcon, Trash2 } from 'lucide-react'; @@ -75,7 +81,7 @@ export function SettingsPage() { return (
} bordered /> -
mutation.mutate(v))} className="grid max-w-3xl gap-8"> + mutation.mutate(v))} className="grid w-full gap-8">

Push notifications

{fields.length === 0 &&

No defaults defined.

} - {fields.map((f, idx) => ( -
- - - - -
- ))} + {fields.length > 0 && ( + + + + Key + Value + Description + + Actions + + + + + {fields.map((f, idx) => ( + + + + + + + + + + + + + + + ))} + +
+ )} {mutation.error && {(mutation.error as ApiError).message}} diff --git a/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js b/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js new file mode 100644 index 00000000..7e5bf4bc --- /dev/null +++ b/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js @@ -0,0 +1,121 @@ +'use strict'; + +// Variables seeded into the default_container_env_vars setting for the +// base/sssd.conf.template. Only SSSD_LDAP_URI and SSSD_LDAP_TLS_REQCERT +// carry default values; the remaining variables are intentionally left +// blank so that sssd falls back to its builtin defaults. +const SSSD_DEFAULTS = [ + { + key: 'SSSD_LDAP_URI', + value: 'ldaps://ldap1:636, ldaps://ldap2:636', + description: 'Comma-separated list of LDAP server URIs sssd connects to' + }, + { + key: 'SSSD_LDAP_TLS_REQCERT', + value: 'allow', + description: 'TLS certificate validation policy for LDAP connections (e.g. never, allow, try, demand)' + }, + { + key: 'SSSD_LDAP_SCHEMA', + value: '', + description: 'LDAP schema type — leave blank to use the sssd builtin default' + }, + { + key: 'SSSD_LDAP_SEARCH_BASE', + value: '', + description: 'Base DN for LDAP searches — leave blank to use the sssd builtin default' + }, + { + key: 'SSSD_LDAP_USER_SEARCH_BASE', + value: '', + description: 'Base DN for LDAP user searches — leave blank to use the sssd builtin default' + }, + { + key: 'SSSD_LDAP_GROUP_SEARCH_BASE', + value: '', + description: 'Base DN for LDAP group searches — leave blank to use the sssd builtin default' + }, + { + key: 'SSSD_LDAP_DEFAULT_BIND_DN', + value: '', + description: 'DN used to bind to the LDAP server — leave blank to use the sssd builtin default' + }, + { + key: 'SSSD_DEFAULT_AUTHTOK_TYPE', + value: '', + description: 'Type of the LDAP bind authentication token — leave blank to use the sssd builtin default' + }, + { + key: 'SSSD_DEFAULT_AUTHTOK', + value: '', + description: 'LDAP bind authentication token — leave blank to use the sssd builtin default' + } +]; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface) { + const [rows] = await queryInterface.sequelize.query( + `SELECT value FROM "Settings" WHERE key = 'default_container_env_vars'` + ); + + let existing = []; + if (rows.length > 0) { + try { + const parsed = JSON.parse(rows[0].value); + if (Array.isArray(parsed)) { + existing = parsed; + } else if (typeof parsed === 'object' && parsed !== null) { + // Migrate from old flat-object format {KEY: value} to array format + existing = Object.entries(parsed).map(([key, value]) => ({ key, value, description: '' })); + } + } catch (_) { + existing = []; + } + } + + const existingKeys = new Set(existing.map(e => e.key)); + const toAdd = SSSD_DEFAULTS.filter(e => !existingKeys.has(e.key)); + if (toAdd.length === 0) return; // all keys already present + + const merged = [...existing, ...toAdd]; + const now = new Date(); + + if (rows.length > 0) { + await queryInterface.sequelize.query( + `UPDATE "Settings" SET value = :value, "updatedAt" = :now WHERE key = 'default_container_env_vars'`, + { replacements: { value: JSON.stringify(merged), now } } + ); + } else { + await queryInterface.bulkInsert('Settings', [{ + key: 'default_container_env_vars', + value: JSON.stringify(merged), + createdAt: now, + updatedAt: now + }]); + } + }, + + async down(queryInterface) { + const [rows] = await queryInterface.sequelize.query( + `SELECT value FROM "Settings" WHERE key = 'default_container_env_vars'` + ); + if (rows.length === 0) return; + + let existing = []; + try { + const parsed = JSON.parse(rows[0].value); + existing = Array.isArray(parsed) ? parsed : []; + } catch (_) { + return; + } + + const keysToRemove = new Set(SSSD_DEFAULTS.map(e => e.key)); + const reverted = existing.filter(e => !keysToRemove.has(e.key)); + + await queryInterface.sequelize.query( + `UPDATE "Settings" SET value = :value, "updatedAt" = :now WHERE key = 'default_container_env_vars'`, + { replacements: { value: JSON.stringify(reverted), now: new Date() } } + ); + } +}; From 04dd9aad4805da798d3af5d32321efdd715537aa Mon Sep 17 00:00:00 2001 From: Robert Gingras Date: Thu, 4 Jun 2026 10:43:31 -0400 Subject: [PATCH 5/6] fix: remove incorrect description from Wazuh vars --- .../seeders/20260311000000-seed-wazuh-env-vars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create-a-container/seeders/20260311000000-seed-wazuh-env-vars.js b/create-a-container/seeders/20260311000000-seed-wazuh-env-vars.js index 19782412..7ef8fc13 100644 --- a/create-a-container/seeders/20260311000000-seed-wazuh-env-vars.js +++ b/create-a-container/seeders/20260311000000-seed-wazuh-env-vars.js @@ -12,7 +12,7 @@ const WAZUH_DEFAULTS = [ { key: 'WAZUH_REGISTRATION_PASSWORD', value: '', - description: 'Enrollment password for Wazuh agent registration — deleted from /etc/environment inside the container immediately after first-boot enrollment completes' + description: 'Enrollment password for Wazuh agent registration' } ]; From 5c870717f78537ec17a33f38a43b90d2609ec311 Mon Sep 17 00:00:00 2001 From: Robert Gingras Date: Thu, 4 Jun 2026 10:45:39 -0400 Subject: [PATCH 6/6] grammar: remove unnessecary emdashes --- .../seeders/20260604000000-seed-sssd-env-vars.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js b/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js index 7e5bf4bc..b317aea6 100644 --- a/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js +++ b/create-a-container/seeders/20260604000000-seed-sssd-env-vars.js @@ -18,37 +18,37 @@ const SSSD_DEFAULTS = [ { key: 'SSSD_LDAP_SCHEMA', value: '', - description: 'LDAP schema type — leave blank to use the sssd builtin default' + description: 'LDAP schema type. Leave blank to use the sssd builtin default' }, { key: 'SSSD_LDAP_SEARCH_BASE', value: '', - description: 'Base DN for LDAP searches — leave blank to use the sssd builtin default' + description: 'Base DN for LDAP searches. Leave blank to use the sssd builtin default' }, { key: 'SSSD_LDAP_USER_SEARCH_BASE', value: '', - description: 'Base DN for LDAP user searches — leave blank to use the sssd builtin default' + description: 'Base DN for LDAP user searches. Leave blank to use the sssd builtin default' }, { key: 'SSSD_LDAP_GROUP_SEARCH_BASE', value: '', - description: 'Base DN for LDAP group searches — leave blank to use the sssd builtin default' + description: 'Base DN for LDAP group searches. Leave blank to use the sssd builtin default' }, { key: 'SSSD_LDAP_DEFAULT_BIND_DN', value: '', - description: 'DN used to bind to the LDAP server — leave blank to use the sssd builtin default' + description: 'DN used to bind to the LDAP server. Leave blank to use the sssd builtin default' }, { key: 'SSSD_DEFAULT_AUTHTOK_TYPE', value: '', - description: 'Type of the LDAP bind authentication token — leave blank to use the sssd builtin default' + description: 'Type of the LDAP bind authentication token. Leave blank to use the sssd builtin default' }, { key: 'SSSD_DEFAULT_AUTHTOK', value: '', - description: 'LDAP bind authentication token — leave blank to use the sssd builtin default' + description: 'LDAP bind authentication token. Leave blank to use the sssd builtin default' } ];