Skip to content

AD Provider: Support initial password inputs #154

@blindzero

Description

@blindzero

Problem Statement

Creating AD users via IdLE.Step.CreateIdentity + IdLE.Provider.AD currently fails in many real-world domains because AD password policy requires an initial password when the account is enabled. Users also need a safe and ergonomic way to provide an initial password to IdLE.

Constraints:

  • Workflows are .psd1 data files and should not embed secrets directly.
  • Template substitution currently yields strings, so a SecureString cannot be embedded directly.
  • For operational onboarding, an initial password may need to be supplied interactively (and is typically rotated on first login).

Goal: Allow providing an initial password to the AD Provider in a controlled, explicit, and well-documented way.

Proposed Solution

Extend the AD Provider/Adapter password input handling for CreateIdentity(...) by supporting three input modes:

1) SecureString input (power users/tests)

If With.AccountPassword is a SecureString, use it directly for New-ADUser -AccountPassword.

2) ProtectedString input (recommended for templating)

If With.AccountPassword is a string, treat it as a ProtectedString produced by ConvertFrom-SecureString (no -AsPlainText).

  • Convert using ConvertTo-SecureString (without -AsPlainText).
  • If conversion fails, fail fast with an actionable error explaining the expected format (ProtectedString from ConvertFrom-SecureString) and the DPAPI scope limitation.

3) Explicit PlainText input via With.AccountPasswordAsPlainText (escape hatch)

Allow plaintext password input only via a dedicated, explicit property:

  • With.AccountPasswordAsPlainText = '<plaintext>'

Rules:

  • This is treated as a secret and MUST be redacted from:
    • logs, events, errors, plan export, verbose/debug output
  • Convert with ConvertTo-SecureString -AsPlainText -Force.
  • Never support plaintext via With.AccountPassword (to avoid accidental use).

Precedence / validation

  • If both With.AccountPassword and With.AccountPasswordAsPlainText are provided: fail fast (ambiguous).
  • If password input is provided (any mode), AD Provider sets/uses it for account creation and can proceed with enabling the account if requested.

Documentation (mandatory)

Add a dedicated AD Provider documentation section:

  • “Providing initial passwords safely”
    • ProtectedString pattern (recommended):
      • generate protected string at runtime
      • put into Request.Variables
      • use template substitution into With.AccountPassword
    • Plaintext pattern (explicit escape hatch):
      • use With.AccountPasswordAsPlainText
      • strong warnings and redaction guarantees
  • Explain DPAPI constraints for ProtectedString:
    • works only when encryption and decryption happen under the same Windows user and machine (unless a key-based approach is used later).

Alternatives Considered

  • Do not support plaintext at all.

    • Rejected: onboarding often requires a human-readable initial password; an explicit escape hatch is acceptable if it is opt-in and strongly redacted.
  • Require a secret store capability first.

    • Rejected: would block basic AD joiner workflows; provider-level support is needed now.

Impact

  • Does this affect existing workflows?

    • Additive. Existing workflows remain unchanged.
    • Enables new workflows to pass initial passwords without embedding secrets in .psd1.
  • Any backward compatibility concerns?

    • Low. Introduces new optional With.* properties and conversion behavior for With.AccountPassword strings.

Additional Context

Acceptance Criteria

  • With.AccountPassword supports:
    • SecureString
    • ProtectedString (ConvertFrom-SecureString output)
  • With.AccountPasswordAsPlainText supports plaintext input explicitly.
  • Redaction:
    • Password values (both protected and plaintext) never appear in events/results by default, logs, error objects, or plan exports.
  • Clear error messages on invalid formats and on ambiguous configuration.

Examples

ProtectedString via Request.Variables

$pwSecure = Read-Host "Initial password" -AsSecureString
$req = New-IdleLifecycleRequest -LifecycleEvent 'Joiner' -Variables @{
  AdInitialPassword = ($pwSecure | ConvertFrom-SecureString)
}

Workflow:

With = @{
  AuthSessionName = 'AD'
  AccountPassword = '{{ Request.Variables.AdInitialPassword }}'
  # ...
}

Explicit plaintext (escape hatch)

With = @{
  AuthSessionName            = 'AD'
  AccountPasswordAsPlainText = 'Temp-Pa55w0rd!'
  # ...
}

Metadata

Metadata

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions