Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

lldap-operator is a Kubernetes operator that manages lldap users and groups as native Kubernetes resources via Custom Resource Definitions (CRDs).

Note: This project is in early development. APIs are not yet stable.

Features

  • Declare lldap users and groups as Kubernetes CRDs
  • Reconcile desired state with lldap via its GraphQL API
  • Password management through Kubernetes Secret references
  • Standard operator patterns: status conditions, finalizers, observed generation

Installation

Prerequisites

  • A running Kubernetes cluster (v1.26+)
  • Helm v3
  • An accessible lldap instance

Quick Start

helm repo add lldap-operator \
  https://lukidoescode.github.io/lldap-operator
helm install lldap-operator \
  lldap-operator/lldap-operator

Configuration

See the Configuration Reference for all available Helm values.

Configuration Reference

Helm Values

Operator Environment Variables

CRD Reference

The lldap-operator manages the following Custom Resource Definitions:

KindDescriptionStatus
LldapUserManages lldap user accountsSchema only
LldapGroupManages lldap groupsSchema only
LldapMembershipManages group membership relationshipsSchema only
LldapAttributeSchemaManages custom attribute schemasSchema only

All resources use the API group lldap-operator.lukidoescode.com/v1alpha1.

LldapUser

An LldapUser resource declares an lldap user account managed by the operator.

Each resource must carry the lldap-operator.lukidoescode.com/lldap-instance label whose value selects which lldap instance the user belongs to. The operator ignores resources without this label.

Example

apiVersion: lldap-operator.lukidoescode.com/v1alpha1
kind: LldapUser
metadata:
  name: alice
  labels:
    lldap-operator.lukidoescode.com/lldap-instance: default
spec:
  username: "alice.smith"
  email: "alice.smith@example.com"
  displayName: "Alice Smith"
  firstName: "Alice"
  lastName: "Smith"
  passwordPolicy: Manage
  passwordSecretRef:
    name: alice-password
    key: password
  attributes:
    - name: department
      value:
        - "Engineering"
---
apiVersion: v1
kind: Secret
metadata:
  name: alice-password
type: Opaque
stringData:
  password: "change-me-on-first-login"

Spec Fields

FieldTypeRequiredDescription
usernamestringyesLDAP username (1–64 chars, [a-zA-Z0-9._-])
emailstringyesEmail address
displayNamestringnoDisplay name
firstNamestringnoFirst name
lastNamestringnoLast name
attributesAttributeValue[]noCustom attribute values; each requires a corresponding LldapAttributeSchema
passwordPolicystringnoOne of Manage (default), InitialOnly, Ignore
passwordSecretRefobjectnoReference to a Secret containing the password
passwordSecretRef.namestringyes (when set)Name of the Secret
passwordSecretRef.keystringyes (when set)Key within the Secret containing the password

Validation Rules

The following rules are enforced at admission time by the Kubernetes API server via CRD-embedded CEL expressions (requires Kubernetes 1.25+).

  • Instance label required — rejected with:

    metadata.labels must include 'lldap-operator.lukidoescode.com/lldap-instance' with a non-empty value

    The label must be set to a non-empty string identifying which lldap instance owns this user.

  • Password secret required for managed policies — rejected with:

    spec.passwordSecretRef is required when spec.passwordPolicy is 'Manage' or 'InitialOnly' (only 'Ignore' permits omitting it)

    When passwordPolicy is Manage (the default) or InitialOnly, the operator needs a Secret reference to source the password from. Only Ignore permits omitting passwordSecretRef.

Group memberships are not declared on LldapUser. Use LldapMembership to attach users to groups.

Status

FieldTypeDescription
uuidstringUser UUID assigned by lldap
passwordHashstringHash of the last reconciled password, used to detect Secret changes
observedGenerationint64Last observed resource generation
conditionsCondition[]Standard Kubernetes conditions

LldapGroup

An LldapGroup resource declares an lldap group managed by the operator.

Each resource must carry the lldap-operator.lukidoescode.com/lldap-instance label whose value selects which lldap instance the group belongs to.

Example

apiVersion: lldap-operator.lukidoescode.com/v1alpha1
kind: LldapGroup
metadata:
  name: engineering
  labels:
    lldap-operator.lukidoescode.com/lldap-instance: default
spec:
  displayName: "Engineering"
  attributes:
    - name: costCenter
      value:
        - "1234"

Spec Fields

FieldTypeRequiredDescription
displayNamestringyesGroup display name (1–128 chars)
attributesAttributeValue[]noCustom attribute values; each requires a corresponding LldapAttributeSchema with target: Group

Status

FieldTypeDescription
groupIdintegerGroup ID assigned by lldap
uuidstringGroup UUID assigned by lldap
observedGenerationint64Last observed resource generation
conditionsCondition[]Standard Kubernetes conditions

LldapMembership

An LldapMembership resource binds an lldap user to an lldap group.

Each resource must carry the lldap-operator.lukidoescode.com/lldap-instance label whose value selects which lldap instance the membership applies to.

The userName and groupName fields reference the lldap-side identifiers (the spec.username of an LldapUser and the spec.displayName of an LldapGroup), not Kubernetes metadata.name values.

Example

apiVersion: lldap-operator.lukidoescode.com/v1alpha1
kind: LldapMembership
metadata:
  name: alice-engineering
  labels:
    lldap-operator.lukidoescode.com/lldap-instance: default
spec:
  userName: "alice.smith"
  groupName: "Engineering"

Spec Fields

FieldTypeRequiredDescription
userNamestringyeslldap username (1–64 chars)
groupNamestringyeslldap group display name (1–128 chars)

Validation Rules

Admission-time validation (CEL)

  • Instance label required — rejected with:

    metadata.labels must include 'lldap-operator.lukidoescode.com/lldap-instance' with a non-empty value

    The label must be set to a non-empty string identifying which lldap instance the membership belongs to.

Reconcile-time validation (reference checks)

The reconciler verifies cross-resource references before applying a membership:

  • The referenced LldapUser (matched by spec.username equal to this resource’s spec.userName) must exist in the same namespace as the membership.
  • The referenced LldapGroup (matched by spec.displayName equal to this resource’s spec.groupName) must exist in the same namespace as the membership.
  • All three resources (user, group, membership) must carry the same lldap-operator.lukidoescode.com/lldap-instance label value.

On failure the reconciler returns a hard error and the membership’s Ready condition is set to False with one of these reasons: UserNotFound, GroupNotFound, MissingNamespace, MissingInstanceLabel.

Note: the reconciler is not yet wired up. The validation function (validate_membership_references) is implemented in lldap-operator-reconciler and will be invoked once the reconciler is built.

Status

FieldTypeDescription
observedGenerationint64Last observed resource generation
conditionsCondition[]Standard Kubernetes conditions

LldapAttributeSchema

An LldapAttributeSchema resource declares a custom attribute on either the user or group entity in lldap.

Each resource must carry the lldap-operator.lukidoescode.com/lldap-instance label whose value selects which lldap instance owns the attribute schema.

lldap does not support mutating an attribute schema after creation: the attribute can only be added or deleted. Updates to a schema’s type or flags require deleting and recreating the resource. Validation enforcing this constraint is tracked separately.

Example

apiVersion: lldap-operator.lukidoescode.com/v1alpha1
kind: LldapAttributeSchema
metadata:
  name: department
  labels:
    lldap-operator.lukidoescode.com/lldap-instance: default
spec:
  attributeName: "department"
  attributeType: "String"
  target: "User"
  isList: false
  isVisible: true
  isEditable: true

Spec Fields

FieldTypeRequiredDescription
attributeNamestringyesAttribute identifier (1–64 chars, [a-zA-Z][a-zA-Z0-9_]*)
attributeTypestringyesOne of String, Integer, JpegPhoto, DateTime
targetstringyesOne of User, Group
isListboolnoWhether the attribute holds multiple values
isVisibleboolnoWhether the attribute is visible to LDAP clients
isEditableboolnoWhether the attribute is editable through the lldap UI

Status

FieldTypeDescription
observedGenerationint64Last observed resource generation
conditionsCondition[]Standard Kubernetes conditions

Multi-Instance Deployment

Password Management

Troubleshooting

Architecture

This chapter will describe the architecture of how the LLDAP operator fits into the eco system of a Kubernetes deployment and how to employ it with Kyverno and OPA/Gatekeeper.

Development Guide

This chapter is for contributors who want to build and test the operator locally.

Prerequisites

Local Setup

./scripts/local-dev-setup.sh

This creates a kind cluster, deploys an lldap test instance, and installs the CRDs.

Building

cargo build --workspace

Running Tests

cargo test --workspace

Code Quality

Before submitting changes, ensure the following pass:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace