Guide 04

Scenario YAML

Users, groups, ACLs, tokens, and lab policy are declared in a labldap.dev/v1alpha1 LabScenario file. Bootstrap compiles that file and writes real 389 DS entries. The YAML is the lab definition — not an in-memory directory.

Users and groups

apiVersion: labldap.dev/v1alpha1
kind: LabScenario
metadata:
  name: compose-lab
spec:
  directory:
    suffix: "dc=example,dc=test"
    peopleRDN: "ou=people"
    groupsRDN: "ou=groups"

  users:
    - id: alice
      uid: alice
      passwordFile: /run/secrets/user-alice
      enabled: true
      attributes:
        givenName: Alice
        sn: Anderson
        mail: alice@example.test

  groups:
    - id: staff
      members:
        - user: alice

What it becomes

YAMLDirectory
users[].id / uiduid=,ou=people,
passwordFileuserPassword (hashed by 389 DS)
enabled: falsensAccountLock
attributesextra string attrs (givenName, sn, mail)
groups[].idcn=,ou=groups, (groupOfNames)
members.usermember: uid=…

The shipped Compose lab is deploy/compose/scenario.yaml. Schema: config/schema/v1alpha1.json.

Rules

  • No inline passwords. Point at a passwordFile. make compose-up writes those files under secrets/.
  • Groups cannot be empty. 389 groupOfNames needs a member. Nested groups stay off unless nestedGroups: true.
  • YAML is the compiled baseline, not a live sync loop. UI / REST / MCP can add users later. Soft reset restores this file.
  • Changing the file means re-bootstrap. The running control plane does not remount a new scenario on the fly.
  • allowRawACI: false. Declare acls: in YAML. Do not paste 389 ACI text.

ACLs

  acls:
    - id: staff-read
      principal: { kind: group, ref: staff }
      target: { kind: suffix }
      permissions: [read, search, compare]
      attributes:
        allow: ["*"]
        deny: [userPassword]

That compiles to 389 ACIs. Seed user alice can search the suffix, bind as herself, and cannot read userPassword.

Apply

Edit deploy/compose/scenario.yaml (or set LABLDAP_SCENARIO_FILE), then make compose-up. Bind as a seeded user, not Directory Manager:

ldapsearch -H ldap://127.0.0.1:3389 -ZZ \
  -x -D 'uid=alice,ou=people,dc=example,dc=test' \
  -y secrets/user-alice \
  -b 'dc=example,dc=test' '(uid=alice)'

The shipped suffix is dc=example,dc=test.

Baseline vs runtime

PathWhat happens
Scenario YAMLCompiled at bootstrap. Soft reset target.
UI / REST / MCPLive mutations on 389 DS until reset or volume wipe.
make compose-resetDestroy the volume, apply the YAML again.

Full version: docs/guides/scenario.md.