Add LDAP byte-pump tunnel, secrets rendering, and IAM engine

See CHANGELOG.md for the full breakdown. Summary:

- ldap_tunnel.go: serves a local unix socket for SSSD/PAM and relays raw
  bytes to the SSO over the existing WSS channel (ldap_tunnel messages);
  the agent never parses LDAP (DESIGN.md §4). Adds safeWriter to
  serialize WebSocket writes now that telemetry, heartbeat, the LDAP
  tunnel, and command responses all share one connection.
- secrets.go: renders local templates ({{ bao "path#key" }} placeholders)
  by fetching node-scoped values from the SSO and writing the target
  atomically at 0600, on a signed render_secrets command (DESIGN.md §5).
  demo/ has minimal bash + Node consumers of the rendered file.
- iam.go: applies signed node IAM pushes -- sudoers.d rules (visudo -c
  validated), SSH AuthorizedKeysCommand keys, /etc/security/access.conf,
  and revocation via sss_cache -E + pkill -u (DESIGN.md §6).
- Capability reporting: the agent's enabled capabilities ride along in
  its discovery frame so the SSO can show them in the Directory.
- DESIGN.md: the v2 protocol design this implements.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 17:12:58 -04:00
parent d128807431
commit 8f0158eb9f
21 changed files with 1392 additions and 20 deletions
+20
View File
@@ -70,6 +70,24 @@ All messages are exchanged as JSON objects following the `WSMessage` structure.
}
```
### 2.1 `ldap_tunnel` — the LDAP byte pump (DESIGN.md §4)
The agent serves a local LDAP socket for SSSD/PAM. It is a **pure byte pump**:
the agent forwards raw LDAP bytes to the SSO, which relays them into its real
OpenLDAP and pipes the response back. Neither side parses LDAP.
- **Type**: `ldap_tunnel` (bidirectional — sent by both agent and SSO)
- **Payload**:
- `conn_id`: (string) correlates one local LDAP connection.
- `data`: (string, optional) base64-encoded raw LDAP bytes.
- `close`: (bool, optional) ends the connection.
The agent reads its local socket and sends `data` chunks up; the SSO relays them
into OpenLDAP and sends OpenLDAP's response chunks back down; the agent writes
them to the socket. `close:true` ends a connection. When the WSS is down the
agent cannot forward bytes, so it closes local socket connections and SSSD falls
back to its local cache.
## 3. Client $\rightarrow$ Server Messages
### 3.1 Discovery (One-time & On-Change)
@@ -153,6 +171,8 @@ These commands **require** an Ed25519 signature in the payload. The agent verifi
| `configure_ldap` | `{ "config": "...", "signature": "..." }` | Writes `/etc/sssd/sssd.conf` and restarts `sssd`. |
| `arbitrary_bash` | `{ "script": "...", "signature": "..." }` | Executes raw bash script. |
| `update_binary` | `{ "url": "...", "sha256": "...", "signature": "..." }` | Downloads, verifies, and replaces the agent binary. |
| `render_secrets` | `{ "signature": "..." }` | Renders the configured secret templates to their targets (DESIGN.md §5). |
| `iam_apply` | `{ "node_id", "revision", "access_control", "signature" }` | Applies node IAM: sudo rules, SSH keys, access control, revocation (DESIGN.md §6). |
## 5. Cryptographic Verification Process