schema_version: 1 · file-referenced secrets · memory overlay

The lab is
a YAML file.

There is no persisted AAA database. Users, groups, clients, tokens, and listeners live in config/taclab.yaml. Passwords and shared secrets live in files under secrets/. Canonical write-up: docs/BASELINE.md.

State files after labgen

PathHolds
config/taclab.yamlUsers, groups, clients, bootstrap tokens, listeners, policy
secrets/api_admin_tokenREST / MCP / UI bearer
secrets/lab_admin_argon2idASCII/PAP verifier for lab-admin
secrets/lab_admin_enable_argon2idENABLE verifier
secrets/lab_admin_challenge_secretCHAP / MS-CHAP (not hashed)
secrets/lab_readonly_argon2idASCII/PAP for lab-readonly
secrets/lab_switches_tacacs_secretLegacy device shared secret
secrets/PASSWORDS.txtHuman crib only — daemon never reads it

Unknown YAML fields fail closed. taclabd never rewrites the baseline. Runtime overlay is memory-only.

Stock personas

Users

id is the TACACS username

lab-admin → group administrators (priv-lvl 15). lab-readonlyreadonly (priv-lvl 1). lab-disabled is off. UsernameCasePreserved — not lowercased.

Groups

Flat. Default deny.

services[] never decide a cmd. command_rules[] never decide a session. YAML permit is an alias of permit_add.

Clients

Devices, not people

lab-switches on :49 with a per-client secret. secure-routers on :300 with mTLS. Match uses the TCP peer TacLab sees.

Credentials

Three different materials

Argon2id login verifier for ASCII/PAP. Separate challenge secret for CHAP/MS-CHAP. Separate ENABLE verifier. Never mix them.

Add a durable user

users:
  - id: netops
    display_name: Network operations
    enabled: true
    group_ids: [readonly]
    credentials:
      login:
        verifier:
          file: /run/secrets/netops_argon2id
    restrictions:
      client_ids: []

Then add netops_argon2id to compose.yaml (service list and top-level secrets:), put the PHC file in secrets/, taclabd validate, and docker compose up -d. Reload alone cannot mount a new Docker secret.

Two lifetimes

Durable

Edit files, reload

YAML + secret files survive restart. That is the lab you can check in (minus secrets) and rebuild.

Ephemeral

UI / REST / MCP

taclab.users.create accepts a password once and stores Argon2id. Gone on restart or runtime.reset.