Skip to content
Draft
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
42422f5
feat(agent): add structured runtime health model
Jul 28, 2026
e379eb2
feat(agentd): supervise runtime configuration
Jul 28, 2026
6d347ff
feat(agent): coordinate listener shutdown
Jul 28, 2026
a83fc0d
feat(agent): publish upstream availability
Jul 28, 2026
e803b1a
feat(agent): serve standard gRPC health
Jul 28, 2026
684466e
feat(agentd): add health probe executable
Jul 28, 2026
532f9e1
feat(agentd): add explicit host integration
Jul 28, 2026
69c90ce
test(agent): complete P1 health coverage
Jul 28, 2026
e294468
test(agentd): add Linux health process smoke
Jul 28, 2026
115aa73
docs(agentd): document P1 health hosting model
Jul 28, 2026
b7e4c68
update packages
Jul 28, 2026
77169a7
Potential fix for pull request finding
Rod-Persky Jul 28, 2026
822cc29
build(config): pin YANG generation inputs
Jul 28, 2026
a3e00b9
feat(config): enable central credential features
Jul 28, 2026
23d4d75
feat(config): generate central credential shapes
Jul 28, 2026
14949d8
feat(config): validate central credential choices
Jul 28, 2026
8576a13
test(config): prove central bundle preservation
Jul 28, 2026
e4c5409
feat(config): inspect central credential references
Jul 28, 2026
67d51c4
feat(credentials): add provider-neutral resolution
Jul 28, 2026
41d561c
test(credentials): enforce secret material safety
Jul 28, 2026
a05d47f
test(credentials): complete P2 acceptance matrix
Jul 28, 2026
076110c
docs(credentials): complete P2 integration guidance
Jul 28, 2026
7e362f9
Merge branch 'main' into dev/rodpersky/p2-all-changes
Rod-Persky Jul 28, 2026
b9b1758
fix(credentials): key resolved results by slot
Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
*.sh text eol=lf
*.service text eol=lf

libraries/tacacsrs_config/src/generated.rs text eol=lf
libraries/tacacsrs_config/yang/*.ini text eol=lf
libraries/tacacsrs_config/yang/*.json text eol=lf
libraries/tacacsrs_config/yang/*.py text eol=lf
libraries/tacacsrs_config/yang/*.txt text eol=lf

executables/*/debian/maintainer-scripts/* text eol=lf
libraries/*/debian/maintainer-scripts/* text eol=lf

Expand Down
18 changes: 18 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"libraries/tacacsrs_agent_ipc_emulator",
"libraries/tacacsrs_agent",
"libraries/tacacsrs_config",
"libraries/tacacsrs_credential_resolution",
"libraries/tacacsrs_datastore",
"libraries/tacacsrs_cli_datastore",
"libraries/tacacsrs_sonic",
Expand Down
20 changes: 20 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,26 @@ cp generated_types.rs ../src/generated.rs

`expand_yang_tree.py` fetches the upstream IETF YANG modules and passes local project modules from `libraries/tacacsrs_config/yang/modules/` to `pyang`. The `feature-flags.ini` file controls both upstream features and project features such as `tacacsrs:psk-dhe-ke-hello-params`.

The upstream `YangModels/yang` commit is pinned in `expand_yang_tree.py` and recorded with source/input/output SHA-256 values in `generation-manifest.json`. The cache must be a detached HEAD at that exact commit. Use `--clean` to deliberately replace a stale cache; the generator never silently uses another revision.

Verify source identity, manifest hashes, two-run determinism, and checked-in output before committing generated changes:

```bash
cd libraries/tacacsrs_config/yang
python -m unittest -v test_expand_yang_tree.py
python verify_generated.py --clean
```

The verifier compares canonical LF content so Windows and Linux checkouts produce the same result. `.gitattributes` keeps generation inputs and outputs at LF. Do not recreate `feature-flags.ini` with `--list-features` without reviewing every value because that command emits all discovered features as enabled and can erase deliberate `false` selections.

The reviewed feature map enables RFC 9950 central keystore and central truststore support. Generated direct and bundled model paths include:

- structured central asymmetric-key and certificate references for client certificate identity;
- a central symmetric-key reference for TLS 1.3 EPSK while preserving identity, hash, context, target, and group fields;
- central CA and end-entity certificate-bag references for server authentication.

Do not hand-edit these shapes in `src/generated.rs`. `tacacsrs-config` validates generated inline-versus-central choices and preserves central values as opaque strings. It expands only config-local bundles. `tacacsrs-credential-resolution` owns provider-neutral request planning, secret-safe material, and closed result matching. SONiC reference grammar, filesystem retrieval, watching, permission checks, refresh policy, and runtime networking projection belong to the P3 provider/integration layer.

After regenerating, run the workspace formatting, clippy, build, and test commands before committing to ensure the emitted code still matches repository expectations.

## CI/CD Overview
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ See the [Plain TACACS+ to TACACS+ over TLS Transition Guide](docs/tacacs-plus-tl
| **tacon** | Interactive TACACS+ test application for authentication, authorization, accounting, and transport validation across plain TCP, TLS, TLS mTLS, TLS PSK, and TLS PSK-DHE |
| **tacacsrs-agentd** | Central daemon executable that hosts `tacacsrs-agent`, maintains persistent upstream connections, and provides automatic failover |
| **tacacsrs-agent-ipc-emulatord** | OPA/Rego-driven gRPC IPC emulator for integration tests that exercise `ServiceClient` clients without a live daemon |
| **tacacsrs-config** | YANG JSON configuration crate for `ietf-system-tacacs-plus` parsing, validation, and runtime mapping |
| **tacacsrs-config** | Open YANG JSON model for `ietf-system-tacacs-plus` parsing, validation, and config-local bundle enumeration |
| **tacacsrs-credential-resolution** | Provider-neutral central credential plans, secret-safe resolved material, and closed request/result matching |
| **session-wrapper** | Linux session wrapper POC for TACACS+ command authorization via seccomp user notifications |

## Workspace Architecture
Expand All @@ -53,9 +54,11 @@ tacacsrs-agent ────┬──► tacacsrs-agent-client

tacacsrs-agent-ipc-emulatord ───► tacacsrs-agent-ipc-emulator
└──► tacacsrs-agent-client

tacacsrs-credential-resolution ──► tacacsrs-config
```

`tacacsrs-config` is the entry point for RFC 7951 YANG JSON parsing. It owns the generated `ietf-system-tacacs-plus` Rust types, resolves credential references, validates YANG-specific choice constraints, and maps validated data into runtime connection settings shared by `tacon` and `tacacsrs-agentd`.
`tacacsrs-config` is the entry point for RFC 7951 YANG JSON parsing. It owns the generated `ietf-system-tacacs-plus` Rust types, validates YANG-specific constraints, and expands config-local credential bundles while preserving external central references as opaque values. `tacacsrs-credential-resolution` turns those references into typed provider-neutral requests and validates resolved results. Provider-specific retrieval and runtime connection projection are separate integration concerns.

## Documentation

Expand All @@ -67,6 +70,7 @@ tacacsrs-agent-ipc-emulatord ───► tacacsrs-agent-ipc-emulator
- [Plain TACACS+ to TACACS+ over TLS Transition Guide](docs/tacacs-plus-tls-transition.md) — Local proxy cutover plan for `pam_tacplus`, `audisp-tacplus`, and similar clients
- [tacacsrs-agent-ipc-emulator README](libraries/tacacsrs_agent_ipc_emulator/README.md) — Rego policy format and in-process/out-of-process IPC emulator usage
- [tacacsrs-config README](libraries/tacacsrs_config/README.md) — YANG JSON schema support, codegen workflow, parsing APIs
- [tacacsrs-credential-resolution README](libraries/tacacsrs_credential_resolution/README.md) — Central credential planning, resolver contracts, and secret-safe material
- [session-wrapper README](executables/session_wrapper/README.md) — Linux seccomp session wrapper architecture and current allow-all behavior
- [Session Wrapper Deployment Guide](docs/session-wrapper.md) — SSH `ForceCommand` integration, configuration examples, security notes, troubleshooting
- [Session Wrapper Testing](docs/session-wrapper-testing.md) — Linux smoke and integration checks for the session wrapper
Expand Down
10 changes: 7 additions & 3 deletions docs/yang-config-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ Use this guide when you need to author, validate, or consume TACACS+ server conf
- RFC 7951 JSON parsing into the generated TACACS+ model.
- Validation for required server data, unique addresses, TLS choice constraints, SNI requirements, key format identities, base64-encoded key material, and config-local credential references.
- Bundle enumeration helpers that inline local `client-credentials` and `server-credentials` references onto server entries.
- Secret-free inspection of central keystore and truststore references.
- A `TacacsPlusServerBuilder` for constructing valid server definitions in Rust.
- A project-owned TACACS+/TLS augmentation for TLS 1.3 PSK-DHE key exchange group selection.

External secret providers are intentionally kept outside this crate. Parse and enumerate configuration first, then pass the resulting server values to a runtime or provider layer that can materialize external secrets.
Central references remain opaque in this crate. Parse and enumerate configuration first, then use `tacacsrs-credential-resolution` to build provider-neutral requests and validate resolved results. Provider-specific retrieval and runtime projection remain separate integration concerns.

## Basic JSON shape

Expand Down Expand Up @@ -59,6 +60,7 @@ The primary entry points are:
| `validate_credential_references(&TacacsPlus)` | Validate config-local credential bundle references. |
| `enumerate_servers(&TacacsPlus)` | Inline shared credential bundles onto every server. |
| `enumerate_server(&TacacsPlus, &str)` | Inline shared credential bundles for one named server. |
| `inspect_central_references(&TacacsPlusServer)` | Inspect typed central usages without retrieving material. |

The module-oriented API is also available for callers that want grouped imports:

Expand Down Expand Up @@ -98,9 +100,11 @@ let server = enumerate_server(&config, "primary")?;
# anyhow::Ok::<()>(())
```

### External secret resolution
### Central credential resolution

External secret material should be resolved after enumeration by a separate runtime or provider layer. That keeps the generated configuration model safe for logging, reporting, and round-tripping while runtime code receives normalized server values.
Build `tacacsrs_credential_resolution::ResolutionPlan` values after enumeration. The resolution crate emits deterministic requests for central certificate-with-key, TLS 1.3 symmetric key, CA bag, and end-entity bag usages. Its async resolver contract returns secret-safe typed material, and `resolve_plan` rejects incomplete or mismatched result sets.

Neither generic crate interprets a central string as a SONiC identifier or filesystem path. P3 supplies provider retrieval, refresh behavior, and projection into networking inputs.

## Programmatic server construction

Expand Down
28 changes: 17 additions & 11 deletions libraries/tacacsrs_config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
- Validation logic for YANG-specific constraints and semantic checks on inline key material
- Config-local credential bundle validation
- Per-server bundle enumeration helpers for `client-credentials` and `server-credentials`
- Secret-free inspection of central keystore and truststore references on enumerated servers
- A reusable `TacacsPlusServerBuilder` for constructing `TacacsPlusServer` values in code
- A project-owned YANG augmentation for TLS 1.3 PSK DHE key exchange group selection

Any future external secret resolution and materialization should live in a separate runtime/provider crate rather than in `tacacsrs-config`.
External secret resolution is defined by `tacacsrs-credential-resolution`. Provider implementations and runtime materialization remain outside `tacacsrs-config`.

## Parsing API

Expand All @@ -31,8 +32,9 @@ The primary entry points are:
- `validate_credential_references(&TacacsPlus)` — validate config-local `credentials-reference` links into shared bundles
- `enumerate_servers(&TacacsPlus)` — inline shared credential bundles onto each `TacacsPlusServer`
- `enumerate_server(&TacacsPlus, &str)` — inline shared credential bundles for one named server
- `inspect_central_references(&TacacsPlusServer)` — inspect opaque central references without retrieving secret material

If external secret providers are introduced, enumerate the servers first and then pass the resulting `TacacsPlusServer` values to that runtime/provider layer.
Enumerate servers before passing them to `tacacsrs-credential-resolution`. Planning rejects unresolved config-local bundle references with an enumerate-first error.

## Multi-layer design

Expand Down Expand Up @@ -66,10 +68,13 @@ validate_credential_references(&config)?;
let server = enumerate_server(&config, "primary")?;
```

### 3) External secret resolution (separate crate)
### 3) Central credential resolution

External secret providers are intentionally handled outside this crate.
After enumeration, pass the resulting `TacacsPlusServer` values to a separate runtime/provider layer for any optional external validation and secret materialization.
Pass each enumerated server to `tacacsrs_credential_resolution::ResolutionPlan::from_server`. The resolution crate extracts deterministic typed requests for central certificate-with-key, TLS 1.3 symmetric key, CA bag, and end-entity bag references. A `CredentialResolver` returns typed material, and `resolve_plan` validates the complete slot/variant-matched result set.

Central references are opaque in both generic crates. They may contain spaces, slashes, traversal-like text, or provider-defined syntax. `tacacsrs-config` enforces generated YANG structure and inline-versus-central choices, but it does not apply SONiC identifier grammar, map references to paths, test existence or permissions, watch files, or retrieve secrets.

P3 provides the SONiC-specific resolver and projects the closed result set into networking inputs.

### Module-oriented API (recommended for most users)

Expand Down Expand Up @@ -128,13 +133,14 @@ assert!(server.is_obfuscation());

The builder is intentionally small. It is meant for runtime construction of valid server shapes, not as a replacement for schema validation or full YANG parsing.

### Future external crypto integration
### Central crypto integration boundary

The intended long-term split is:

- `tacacsrs-config` stays as the open configuration model. It owns RFC 7951 parsing, schema validation, bundle enumeration, and generated YANG types.
- Small derived helpers that are valid before and after secret resolution belong here, in `extensions`, on top of `TacacsPlusServer` and other generated types.
- External crypto providers should sit behind a separate boundary that consumes enumerated `TacacsPlusServer` values and returns a closed runtime representation with concrete material.
- `tacacsrs-credential-resolution` consumes enumerated `TacacsPlusServer` values and returns a closed provider-neutral result set with concrete material.
- Provider implementations and projection into connection-ready networking types remain integration-layer responsibilities.

That keeps the generated config model optimized for round-tripping and reporting, while runtime code gets a provider-agnostic handoff with only the normalized fields needed to connect.

Expand All @@ -146,7 +152,7 @@ The crate includes runnable examples under `examples/`:
- `quick_start_credential_refs.rs` — minimal end-to-end example showing bundle validation and enumeration
- `pipeline_flow.rs` — explicit step-by-step parse/enumerate/external-resolution pipeline
- `model_access.rs` — direct access to generated model types and flags
- External secret-resolution examples should live in a separate runtime/provider crate if that integration is added later.
- The provider-neutral central-resolution example lives in `tacacsrs-credential-resolution`.

Run examples from the workspace root:

Expand All @@ -155,7 +161,7 @@ cargo run -p tacacsrs-config --example quick_start
cargo run -p tacacsrs-config --example quick_start_credential_refs
cargo run -p tacacsrs-config --example pipeline_flow
cargo run -p tacacsrs-config --example model_access
cargo run -p tacacsrs-config --example credential_references
cargo run -p tacacsrs-credential-resolution --example central_resolution
```

## Public API surface
Expand Down Expand Up @@ -189,7 +195,7 @@ Validation checks include:
- Credential references have matching definitions in the same config
- Config-local credential references have matching definitions

To resolve external credentials and materialize them for runtime use, introduce a separate runtime/provider layer after enumeration.
To resolve central credentials, create a `ResolutionPlan` after enumeration and execute it through a `CredentialResolver`. Runtime projection remains outside both generic crates.

This design separates parsing/validation from credential retrieval and enables round-trip safety.

Expand Down Expand Up @@ -222,7 +228,7 @@ For advanced use cases, these lower-level functions are available:

### 3) Runtime types

If runtime secret-materialized server types are introduced later, they should live outside `tacacsrs-config` in a dedicated runtime/provider crate.
Secret-bearing result types live in `tacacsrs-credential-resolution`; connection-ready server types remain outside `tacacsrs-config`.
Shared derived helpers for the generated server model live in `TacacsPlusServerExt`.
Programmatic construction helpers for the generated server model live in `TacacsPlusServerBuilder`.

Expand Down
2 changes: 2 additions & 0 deletions libraries/tacacsrs_config/src/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ impl TacacsPlusServerBuilder {
cleartext_private_key,
cert_data,
}),
central_keystore_reference: None,
}),
tls13_epsk: None,
});
Expand Down Expand Up @@ -259,6 +260,7 @@ impl TacacsPlusServerBuilder {
key_format: None,
cleartext_symmetric_key: Some(cleartext_symmetric_key),
}),
central_keystore_reference: None,
external_identity: external_identity.into(),
hash: EpskSupportedHash::Sha256,
context: None,
Expand Down
Loading
Loading