- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly. - Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps. - Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges. - Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges. - Set up project file for the test project with necessary dependencies and configurations. - Include JSON fixture files for testing purposes.
12 KiB
RFC: StellaOps.Authority.Plugin.Ldap
Status: Accepted – Auth Guild, Security Guild, DevEx Docs sign-off (2025-11-03)
Authors: Plugin Team 4 (Auth Libraries & Identity Providers)
Related initiatives: PLG7 backlog, CORE5 event handlers, DOC4 developer guide
Review log captured in
docs/notes/2025-11-03-authority-plugin-ldap-review.md. Decisions below reflect consensus from Auth Guild, Security Guild, and DevEx Docs walkthroughs held on 2025-11-03.
0. Review Summary (2025-11-03)
- Confirmed plugin charter: deliver offline-friendly LDAP credential verification with deterministic caching and audit parity with the Standard plugin.
- Resolved open questions:
- Client provisioning audit trail: plugin always mirrors credential lifecycle metadata (actor, timestamp, hashed secret reference) into Authority’s Mongo store even when LDAP writes succeed; directory writes remain optional and secrets never persist locally.
- Mutual TLS support: LDAPS client certificates are required for regulated installations; configuration gains optional client certificate bindings with secret-provider integration and deterministic trust-store selection.
- Group-to-role mapping: mappings accept static DN dictionaries and deterministic
regexmatchers; regex captures project to canonical roles via substitution (documented contract for policy automation).
- Follow-up implementation issues filed in
StellaOps.Authority.Plugin.Standard/TASKS.md(see Section 11) to track scaffolding, mutual TLS enablement, audit mirror, and mapping enhancements.
1. Problem Statement
Many on-prem StellaOps deployments rely on existing LDAP/Active Directory domains for workforce identity. The current Standard Mongo-backed plugin requires duplicating users and secrets, which increases operational overhead and violates corporate policy in some regulated environments. We need a sovereign, offline-friendly LDAP plugin that:
- Supports password grant and bootstrap provisioning flows without storing credentials in Mongo.
- Enforces StellaOps security policies (lockout, password policy hints, audit logging) while delegating credential validation to LDAP.
- Operates deterministically in offline or partially connected environments by caching directory metadata when necessary.
2. Goals
- Provide a first-party
StellaOps.Authority.Plugin.Ldapplugin advertisingpasswordand optionalclientProvisioningcapabilities at launch. - Support username/password authentication against LDAP bind operations with configurable DN templates.
- Allow optional bootstrap seeding of service accounts by writing into LDAP (guarded behind explicit configuration) or by mapping to pre-existing entries.
- Surface directory-derived claims (groups, attributes) for downstream authorization via
IClaimsEnricher. - Integrate with Authority lockout telemetry and structured logging without persisting secrets locally.
3. Non-Goals
- Implement multi-factor authentication out of the box (future enhancement once TOTP/WebAuthn strategy is finalised).
- Provide write-heavy directory management (e.g., user creation workflows) beyond optional bootstrap service account seeding.
- Replace the Standard plugin; both must remain supported and selectable per environment.
4. Key Constraints & Assumptions
- Offline-first posture: deployments may operate without outbound internet and with intermittent directory connectivity (e.g., read-only replicas). The plugin must tolerate transient LDAP connectivity failures and degrade gracefully.
- Deterministic behaviour: identical configuration and directory state must yield identical token issuance results. Cached metadata (e.g., group lookups) must have defined expiration.
- Security: No plaintext credential storage; TLS must be enforced for LDAP connections unless explicitly overridden for air-gapped lab environments.
5. High-Level Architecture
- Configuration binding (
ldap.yaml): defines server endpoints, bind strategy, claim mapping, and optional bootstrap overrides. - Connection factory: pooled LDAP connections using a resilient client (preferred dependency:
Novell.Directory.Ldap.NETStandard). - Credential validator (
IUserCredentialStore): performs bind-as-user flow with optional fallback bind using service account when directories disallow anonymous search. - Claims enricher (
IClaimsEnricher): queries group membership/attributes and projects them into canonical roles/claims. - Optional client provisioning (
IClientProvisioningStore): maintains machine/service principals either in Mongo (metadata) or via LDAPserviceConnectionPointentries based on configuration. - Health checks: periodic LDAP
whoamiorsearchprobes surfaced throughAuthorityPluginHealthResult.
Authority Host
├── Plugin Manifest (ldap)
├── Registrar → registers ConnectionFactory, LdapCredentialStore, LdapClaimsEnricher
├── Password Grant Handler → CredentialStore.VerifyPasswordAsync → LDAP Bind
└── Claims Pipeline → ClaimsEnricher.EnrichAsync → LDAP group lookup
6. Configuration Schema (Draft)
connection:
host: "ldaps://ldap.example.internal"
port: 636
useStartTls: false
validateCertificates: true
clientCertificate:
pfxPath: "file:/etc/stellaops/certs/ldap-client.pfx"
passwordSecret: "file:/etc/stellaops/secrets/ldap-client-pfx.txt"
sendChain: true
trustStore:
mode: "system" # system | bundle
bundlePath: "file:/etc/stellaops/trust/ldap-root.pem"
bindDn: "cn=stellaops-bind,ou=service,dc=example,dc=internal"
bindPasswordSecret: "file:/etc/stellaops/secrets/ldap-bind.txt"
searchBase: "dc=example,dc=internal"
usernameAttribute: "uid"
userDnFormat: "uid={username},ou=people,dc=example,dc=internal" # optional template
security:
requireTls: true
allowInsecureWithEnvToggle: false # requires STELLAOPS_LDAP_ALLOW_INSECURE=true
allowedCipherSuites: [] # optional allow-list
referralChasing: false
lockout:
useAuthorityPolicies: true # reuse Authority lockout counters
directoryLockoutAttribute: "pwdAccountLockedTime"
claims:
groupAttribute: "memberOf"
groupToRoleMap:
"cn=stellaops-admins,ou=groups,dc=example,dc=internal": "operators"
"cn=stellaops-read,ou=groups,dc=example,dc=internal": "auditors"
regexMappings:
- pattern: "^cn=stellaops-(?P<role>[a-z-]+),ou=groups,dc=example,dc=internal$"
roleFormat: "{role}" # yields operators/investigate/etc.
extraAttributes:
displayName: "displayName"
email: "mail"
clientProvisioning:
enabled: false
containerDn: "ou=service,dc=example,dc=internal"
secretAttribute: "userPassword"
auditMirror:
enabled: true
collectionName: "ldap_client_provisioning"
health:
probeIntervalSeconds: 60
timeoutSeconds: 5
7. Capability Mapping
| Capability | Implementation Notes |
|---|---|
password |
Bind-as-user validation with Authority lockout integration. Mandatory. Requires TLS and optionally client certificate binding per regulated install posture. |
clientProvisioning |
Optional; when enabled, creates/updates LDAP entries for machine clients and mirrors lifecycle metadata into Mongo for audit parity. |
bootstrap |
Exposed only when bootstrap manifest provides service account credentials AND directory write permissions are confirmed during startup; always records audit mirror entries. |
mfa |
Not supported in MVP. Future iteration may integrate TOTP attributes or external MFA providers. |
8. Operational Considerations
- Offline cache: provide optional Mongo cache for group membership to keep
/readyresponsive if LDAP is temporarily unreachable. Cache entries must include TTL and invalidation hooks. - Secrets management: accept
file:and environment variable references; integrate with existingStellaOps.Configurationsecret providers. - Mutual TLS & trust anchors: support client certificate authentication with deterministic trust-store selection (
systemvs bundled file) to satisfy regulated deployments; surface validation outcomes via health endpoints. - Audit mirror: write deterministic Mongo records capturing provisioning operations (actor, LDAP DN, operation type, hashed secret reference) to align with Authority audit policy even when LDAP is authoritative.
- Observability: emit structured logs with event IDs (
LDAP_BIND_START,LDAP_BIND_FAILURE,LDAP_GROUP_LOOKUP), counters for success/failure, and latency histograms. - Throttling: reuse Authority rate-limiting middleware; add per-connection throttles to avoid saturating directory servers during brute-force attacks.
9. Security & Compliance
- Enforce TLS (
ldaps://or STARTTLS) by default. Provide explicitallowInsecureflag gated behind environment variable for lab/testing only. - Support optional mutual TLS (client cert authentication) with secret-backed PFX loader and deterministic trust bundle selection.
- Support password hash migration by detecting directory lockout attributes and surfacing
RequiresPasswordResetwhen policies demand changes. - Log distinguished names only at
Debuglevel to avoid leaking sensitive structure in default logs. - Coordinate with Security Guild for penetration testing before GA; incorporate audit log entries for bind attempts and provisioning changes.
10. Testing Strategy
- Unit tests: mock LDAP connections to validate DN formatting, error mapping, and capability negotiation.
- Integration tests: run against an ephemeral OpenLDAP container (seeded via LDIF fixtures) within CI. Include mutual TLS handshake verification (valid/expired certs) and offline cache regression (disconnect LDAP mid-test).
- Determinism tests: feed identical LDIF snapshots and configuration to ensure output tokens/claims remain stable across runs.
- Smoke tests:
dotnet testharness plus manualdotnet runscenario verifying/tokenpassword grants,/internal/usersbootstrap with LDAP-backed store, and Mongo audit mirror entries.
11. Implementation Plan
- Scaffold
StellaOps.Authority.Plugin.Ldapproject + companion test project (net10.0,<IsAuthorityPlugin>true). - Implement configuration binding/validation, including secret-backed client certificate + trust-store options and
allowInsecureWithEnvToggle. - Build connection factory + credential store with bind logic, TLS enforcement, and deterministic retry policies.
- Implement claims enricher with regex mapping support and optional Mongo-backed cache layer.
- Add client provisioning store with LDAP write toggles and Mongo audit mirror (
ldap_client_provisioningcollection). - Wire health checks, telemetry, and structured audit events (bind attempts, provisioning, cache fallbacks).
- Deliver bootstrap validation that inspects directory permissions and logs deterministic capability summary.
- Extend developer guide and samples with LDAP configuration guidance; include mutual TLS and regex mapping examples.
- Update docs/TASKS trackers and release notes entry; ensure CI coverage (unit, integration with OpenLDAP, determinism, smoke tests).
12. Resolved Questions
- Audit mirror: Client provisioning always persists lifecycle metadata in Mongo for audit parity; LDAP remains the credential source of truth.
- Mutual TLS: Plugin must support optional client certificate authentication with secret-backed key material and deterministic trust-store selection.
- Group mapping: Provide deterministic regex mapping support to translate directory DNs into Authority roles/scopes without custom scripts.
13. Timeline (Tentative)
- Week 1: RFC review & sign-off.
- Week 2-3: Implementation & unit tests.
- Week 4: Integration tests + documentation updates.
- Week 5: Security review, release candidate packaging.
14. Approval
- Auth Guild Lead: ✅ Approved 2025-11-03 (see review log).
- Security Guild Representative: ✅ Approved 2025-11-03 (see review log).
- DevEx Docs: ✅ Approved 2025-11-03 (see review log).
Please add comments inline or via PR review. Once approved, track execution under PLG7.