Skip to content

Add OIDC support to domain_join#14

Open
JasonN3 wants to merge 12 commits intomainfrom
oidc
Open

Add OIDC support to domain_join#14
JasonN3 wants to merge 12 commits intomainfrom
oidc

Conversation

@JasonN3
Copy link
Owner

@JasonN3 JasonN3 commented Feb 11, 2026

This also updates some of the references to Puppet to OpenVox.

Summary by CodeRabbit

  • New Features

    • Added OpenID Connect (OIDC) support with Microsoft Entra integration and conditional activation.
    • Introduced OIDC parameters (client ID, client secret, tenant) and made username/password optional to enable OIDC-only flows.
    • Added OIDC-specific SSSD configuration and adaptive install/join behavior when OIDC is enabled.
  • Documentation

    • Rebranded to "OpenVox Modules" and updated README/header/footer, install instructions, repo URLs, and tooling references.
  • Tests

    • Updated test expectations to reflect revised file header branding.

@JasonN3 JasonN3 self-assigned this Feb 11, 2026
@JasonN3 JasonN3 added the enhancement New feature or request label Feb 11, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Repository branding and docs renamed from "Puppet Modules" to "OpenVox Modules"; dev tooling URLs updated. domain_join gains OIDC support (new params, optional username/password), conditional SSSD package/template selection, guarded join/smartcard logic, and a new SSSD OIDC ERB template.

Changes

Cohort / File(s) Summary
Branding & README updates
​.readme/header.md, ​.readme/footer.md, README.md
Rename project to "OpenVox Modules", update description and development instructions; change clone URL puppet_modules.gitopenvox_modules.git; replace r10k references with g10k.
Domain Join Documentation
domain_join/README.md
Add OIDC parameters (oidc, client_id, client_secret, tenant_id); change username and sensitive_password types to Optional and update parameter docs.
Domain Join Implementation
domain_join/manifests/init.pp
Add Boolean $oidc and Optional OIDC params; make $username and $sensitive_password optional; validate OIDC vs non-OIDC flows; conditionally install sssd-idp and select sssd.oidc.conf.erb; guard adcli/join and smartcard logic; adjust resource relationships/notifications.
SSSD OIDC template
domain_join/templates/sssd.oidc.conf.erb
New ERB template producing SSSD config for OIDC: idp type/settings, client_id and optional unwrapped client_secret, tenant endpoints, fixed scopes, computed homedir, and nss/pam settings.
Tests
domain_join/spec/classes/domain_join_spec.rb
Update expected file_header test value from 'Puppet managed' to 'OpenVox managed'.

Sequence Diagram(s)

sequenceDiagram
    participant Puppet as Puppet Agent
    participant FS as Filesystem
    participant SSSD as sssd Service
    participant IdP as OIDC Provider
    participant AD as Active Directory (adcli)

    Puppet->>FS: Render sssd.conf (select template based on $oidc)
    alt OIDC = true
        Puppet->>FS: Write sssd.oidc.conf (client_id, optional client_secret, tenant endpoints)
        Puppet->>SSSD: Install `sssd-idp`
        Puppet->>SSSD: Start/Restart sssd
        SSSD->>IdP: Token / userinfo requests (OIDC flows)
    else OIDC = false
        Puppet->>FS: Write sssd.conf
        Puppet->>AD: Run `adcli join` (Exec 'Join')
        Puppet->>SSSD: Install `sssd`
        Puppet->>SSSD: Start/Restart sssd
        SSSD->>AD: AD/LDAP identity lookups
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add OIDC support to domain_join' directly and accurately summarizes the main change in the pull request, which introduces OIDC authentication support to the domain_join module.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch oidc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
domain_join/manifests/init.pp (2)

343-357: ⚠️ Potential issue | 🔴 Critical

Catalog compilation failure: Exec['Enable SSSD Authentication'] subscribes to Exec['Join'], which is not declared when $oidc is true.

When $oidc is true, the Exec['Join'] resource (line 200) is never declared because it's inside the unless $oidc block (line 189). However, Exec['Enable SSSD Authentication'] unconditionally subscribes to Exec['Join'] on line 346. This will cause a catalog compilation error referencing a non-existent resource.

Proposed fix — conditionally subscribe
   exec { 'Enable SSSD Authentication':
     command     => "${enablesssd} ${enable_smartcard}",
-    subscribe   => [
-      Exec['Join'],
-    ],
     path        => $facts['path'],
     refreshonly => true,
     require     => [
       Package['authconfig'],
       Package['oddjob-mkhomedir'],
       Service['oddjobd'],
       Package['sssd'],
       Service['sssd'],
     ],
   }

Then, inside the unless $oidc block, add notification from Exec['Join']:

   exec { 'Join':
     command => $command,
     path    => $facts['path'],
-    notify  => Service['sssd'],
+    notify  => [Service['sssd'], Exec['Enable SSSD Authentication']],
     creates => '/etc/krb5.keytab',
     ...
   }

Alternatively, you could wrap the subscribe in a conditional or use a collector pattern, depending on how you want the OIDC path to trigger Enable SSSD Authentication.


54-78: ⚠️ Potential issue | 🟠 Major

$username and $sensitive_password lack default values, making them still required even for OIDC users.

Although the types were changed to Optional[...], parameters without defaults are still required by the Puppet/OpenVox compiler. OIDC users who don't need AD credentials would have to explicitly pass undef for these. Consider adding = undef defaults and adding validation for the non-OIDC path.

Proposed fix
 class domain_join (
-  Optional[String]                                           $username,
-  Optional[Sensitive[String]]                                $sensitive_password,
+  Optional[String]                                           $username             = undef,
+  Optional[Sensitive[String]]                                $sensitive_password   = undef,
   ...
 ) {

Then add validation near the top of the class body:

  if $oidc {
    if !$client_id or !$tenant_id {
      fail('client_id and tenant_id are required when oidc is true')
    }
  } else {
    if !$username or !$sensitive_password {
      fail('username and sensitive_password are required when oidc is false')
    }
  }
🤖 Fix all issues with AI agents
In `@domain_join/manifests/init.pp`:
- Around line 189-214: The non-OIDC branch interpolates
$sensitive_password.unwrap and $username directly which will crash if those
Optional values are undef; update the code around the exec 'Join' command
generation to guard usage with defined() checks (e.g. if
defined($sensitive_password) and defined($username)) before calling
$sensitive_password.unwrap or interpolating $username, and handle the else case
by either generating a safe no-op/meaningful error message or skipping the exec
resource; specifically modify the blocks that set $command (where
$sensitive_password.unwrap and ${username} are used) to only build the sensitive
command when those variables are defined.
- Around line 154-163: In the conditional package resource for 'sssd' driven by
$oidc, change the package name attribute from name => 'sssd-oidc' to name =>
'sssd-idp' so the correct SSSD OIDC/IdP package is installed; update the package
resource inside the if $oidc { ... } block (the resource declared as package {
'sssd': ... } ) to use 'sssd-idp' as the name.

In `@domain_join/README.md`:
- Around line 213-219: Update the README entry for the client_secret attribute
to reflect the manifest change: change the documented data type from
Optional[String] to Optional[Sensitive[String]] for client_secret (and keep the
same default/description unless the manifest changes it); ensure the README line
referencing `client_secret` uses the exact symbol name `client_secret` and
clearly shows the new data type `Optional[Sensitive[String]]` so docs match the
manifest change.

In `@domain_join/templates/sssd.oidc.conf.erb`:
- Around line 1-20: When OIDC is enabled the template uses `@client_id` and
`@tenant_id` but there is no guard, so rendering with oidc true and missing
client_id/tenant_id produces invalid SSSD config; add a validation in the
manifest that checks the OIDC flag and fails fast if required parameters are
missing (e.g., if $oidc or $enable_oidc is true and either $client_id or
$tenant_id is undef/empty then call fail("...")). Reference the manifest
variables ($oidc, $client_id, $tenant_id) and use the Puppet fail() function to
provide a clear error message instructing the user to supply both values.
- Line 20: The sssd OIDC template currently hardcodes fallback_homedir to
"/home/%u" instead of using the template variable; update the sssd.oidc.conf.erb
template to interpolate the `@sssd_home` template variable for the home base
(preserving the "%u" username placeholder) so it honors the same sssd_home
parameter as the non-OIDC template and handle potential trailing slash in
`@sssd_home` when composing the final path.
- Around line 8-10: Change the Puppet type for client_secret from
Optional[String] to Optional[Sensitive[String]] in the resource/class that
provides `@client_secret`, and update the ERB template sssd.oidc.conf.erb to call
.unwrap when inserting the secret (i.e., use `@client_secret.unwrap` when present)
so the sensitive value is stored as Sensitive in the catalog and only unwrapped
at render time; ensure code paths that pass $client_secret into the template
accept Optional[Sensitive[String]] and handle the nil/absent case the same way
as before.
🧹 Nitpick comments (1)
domain_join/manifests/init.pp (1)

154-158: Nit: attribute ordering — ensure should come before name per Puppet style guide.

Proposed fix
     package { 'sssd':
-      name   => 'sssd-oidc',
       ensure => installed,
+      name   => 'sssd-oidc',
     }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
domain_join/manifests/init.pp (2)

54-78: ⚠️ Potential issue | 🔴 Critical

Missing parameter validation: OIDC and non-OIDC paths require different mandatory parameters.

With $username and $sensitive_password now Optional, and the new OIDC parameters also Optional, there are no guards ensuring the right set is provided for each mode:

  • $oidc = false: $username and $sensitive_password are interpolated into the adcli join command (lines 192/196). If either is undef, $sensitive_password.unwrap will fail at catalog compilation.
  • $oidc = true: $client_id and $tenant_id are presumably consumed by the sssd.oidc.conf.erb template (line 235). If they're undef, the rendered config will be broken.

Add early validation at the top of the class body, e.g.:

Proposed fix
 ) {
+  if $oidc {
+    if $client_id == undef {
+      fail('client_id is required when oidc is true')
+    }
+    if $tenant_id == undef {
+      fail('tenant_id is required when oidc is true')
+    }
+  } else {
+    if $username == undef {
+      fail('username is required when oidc is false')
+    }
+    if $sensitive_password == undef {
+      fail('sensitive_password is required when oidc is false')
+    }
+  }
+
   if $override_domain {

343-357: ⚠️ Potential issue | 🔴 Critical

Catalog compilation will fail when $oidc = true: Exec['Join'] doesn't exist.

Exec['Enable SSSD Authentication'] subscribes to Exec['Join'] (line 346), but Exec['Join'] is only declared inside the unless $oidc block (line 200). When $oidc = true, the resource is absent from the catalog and Puppet will fail with a compilation error referencing a nonexistent resource.

Additionally, because of refreshonly => true, this exec will never trigger in OIDC mode even if the reference is fixed — SSSD authentication enablement (authselect/authconfig) would be skipped entirely. Consider whether this exec should also run in the OIDC path (perhaps triggered by a different event).

Proposed fix — conditionally subscribe
   exec { 'Enable SSSD Authentication':
     command     => "${enablesssd} ${enable_smartcard}",
-    subscribe   => [
-      Exec['Join'],
-    ],
     path        => $facts['path'],
-    refreshonly => true,
     require     => [
       Package['authconfig'],
       Package['oddjob-mkhomedir'],
       Service['oddjobd'],
       Package['sssd'],
       Service['sssd'],
     ],
+    subscribe   => $oidc ? {
+      true  => undef,
+      false => [Exec['Join']],
+    },
+    refreshonly => !$oidc,
   }

If the exec should only run once and not on every Puppet run in OIDC mode, consider adding a creates or unless guard instead.

🧹 Nitpick comments (3)
domain_join/manifests/init.pp (3)

321-341: Silently ignoring $smartcard when $oidc is true.

When $oidc = true, the $smartcard parameter is silently ignored and $enable_smartcard is set to ''. If a user explicitly sets $smartcard => 'required' alongside $oidc => true, there's no feedback that their smartcard configuration is being disregarded. Consider emitting a warning:

if $oidc and $smartcard != 'disabled' {
  warning('Smartcard settings are ignored when OIDC is enabled')
}

121-153: Consider: unnecessary packages installed in OIDC mode.

adcli, samba-common-tools, and samba-common are always installed, even when $oidc = true and no adcli join will occur. This isn't harmful, but wrapping them in unless $oidc (similar to the join exec) would keep the OIDC footprint minimal.


46-53: Documentation for client_secret could clarify its purpose.

The @param client_secret doc says "Optional secret for client" which is vague. It would help to specify when this is needed (e.g., for confidential OIDC clients) and what happens if it's omitted (e.g., public client / device-code flow).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
domain_join/manifests/init.pp (1)

364-375: ⚠️ Potential issue | 🟠 Major

OIDC mode: Exec['Enable SSSD Authentication'] is never triggered.

This exec is refreshonly => true and is only notified by Exec['Join'] (line 221-224), which is skipped entirely when $oidc is true. This means on a fresh OIDC deployment, authselect/pam-auth-update is never run, so SSSD authentication won't actually be enabled in PAM.

Consider adding a notification path for the OIDC case — for example, having File['/etc/sssd/sssd.conf'] or Package['sssd'] notify this exec, or creating a separate trigger for OIDC mode.

🤖 Fix all issues with AI agents
In `@domain_join/manifests/init.pp`:
- Around line 90-97: The validation block is using bare words so the checks
never trigger; change the checks to reference the Puppet variables with sigils
(use !$username and !$sensitive_password) so undef values cause the fail() to
run, and correct the typo in the fail messages ("disbled" -> "disabled"); this
ensures missing values are caught before the Exec['Join'] resource attempts to
.unwrap on undef.
- Around line 84-86: The current validation unconditionally fails when oidc is
enabled if client_secret is undef, but the parameter is declared
Optional[Sensitive[String]] and templates only emit idp_client_secret when
present; either remove the failing check around client_secret (delete the
fail('domain_join: client_secret must be provided when oidc is enabled') block)
so public-client OIDC flows remain supported, or make client_secret truly
required by changing its type from Optional[Sensitive[String]] to
Sensitive[String], update its documentation string to reflect "Required secret
for client" and adjust any templates/conditionals (e.g., idp_client_secret
emission) and callers to always provide client_secret; update references to
client_secret and oidc accordingly.

@JasonN3
Copy link
Owner Author

JasonN3 commented Feb 11, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
domain_join/manifests/init.pp (1)

361-372: ⚠️ Potential issue | 🔴 Critical

Critical: Exec['Enable SSSD Authentication'] is never triggered in the OIDC path.

This exec has refreshonly => true, so it only runs when notified. The only notifier is Exec['Join'] (line 220), which is not declared when $oidc = true (gated at line 204). As a result, authselect/pam-auth-update never runs in the OIDC flow, leaving PAM unconfigured for SSSD — users will be unable to authenticate.

One approach: add an unless guard to make this idempotent instead of relying solely on refreshonly. For example, on RHEL 8+/Fedora, check if sssd is already the active authselect profile:

🐛 Proposed fix
   exec { 'Enable SSSD Authentication':
     command     => "${enablesssd} ${enable_smartcard}",
     path        => $facts['path'],
-    refreshonly => true,
+    unless      => 'authselect current | grep -q sssd',
     require     => [
       Package['authconfig'],
       Package['oddjob-mkhomedir'],

Note: the unless guard above only covers the authselect code path (RHEL 8+/Fedora 37+). For Debian (pam-auth-update) and RHEL 7 (authconfig), you'll need an equivalent idempotency check, or alternatively keep refreshonly but ensure something notifies this exec in the OIDC path (e.g., File['/etc/sssd/sssd.conf'] or Package['sssd']).

🧹 Nitpick comments (2)
domain_join/manifests/init.pp (2)

169-178: Nit: Puppet style guide recommends ensure as the first attribute.

Lines 171–172 place name before ensure. The Puppet style guide convention is to list ensure first for readability and consistency (as done in line 176).

♻️ Suggested reorder
   if $oidc {
     package { 'sssd':
-      name   => 'sssd-idp',
       ensure => installed,
+      name   => 'sssd-idp',
     }

339-359: Consider warning when $smartcard is not 'disabled' but $oidc is true.

Currently, if both $oidc = true and $smartcard != 'disabled' are set, the smartcard setting is silently ignored. A warning() call would help operators notice the misconfiguration.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@domain_join/manifests/init.pp`:
- Line 264: The notify array has extra spaces inside the square brackets causing
puppet-lint to fail; edit the notify attribute for the resource that currently
reads notify  => [ Service['sssd'], Exec['Enable SSSD Authentication'] ], and
remove the space after the opening '[' and before the closing ']' so the bracket
usage is tightly packed (i.e. notify => [Service['sssd'], Exec['Enable SSSD
Authentication']]); keep the same elements Service['sssd'] and Exec['Enable SSSD
Authentication'] unchanged.
🧹 Nitpick comments (2)
domain_join/spec/classes/domain_join_spec.rb (1)

6-24: Consider adding test coverage for the new OIDC code path.

The existing test only exercises the non-OIDC path (oidc => false by default). The new OIDC feature introduces significant conditional logic (validation, package selection, template selection, join suppression). Adding at least one context with oidc => true (and the required client_id/tenant_id) would guard against regressions.

domain_join/manifests/init.pp (1)

339-359: Smartcard settings are silently ignored when oidc is true.

If a user sets both oidc => true and smartcard => 'required', the smartcard configuration is silently dropped. Consider emitting a warning (via warning()) or adding a validation fail() if $smartcard != 'disabled' when $oidc is true, so users aren't surprised by the behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant