sec: fail-closed verification + server-issued enrollment (v1.4.0)
Implements protocol v1.2.0. verifySignature() returned true when no public_key was configured, logging "skipping signature verification". The SSO installer never wrote a public_key, so a default install executed reboot, service_restart, configure_ldap, arbitrary_bash and update_binary UNVERIFIED from anything that could reach its socket. An agent that cannot verify now refuses. Canonicalization also disagreed with the server. Go's encoding/json escapes <, > and & by default; JSON.stringify does not. Any payload containing them hashed differently on each side and failed verification -- for arbitrary_bash that is most real scripts (`>` redirection, `&&`). Now uses json.Encoder with SetEscapeHTML(false), trailing newline trimmed. The SSO now rejects tokens it did not issue. Handles its close codes (4001/4002/4003/4004) and backs off 5 minutes on an enrollment failure instead of retrying every 5s forever. The connect log no longer prints the URL, which carried ?token=. install.sh gains --public-key and warns when none is configured. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,17 @@ The agent will **only** execute commands that are explicitly enabled in its loca
|
||||
### Cryptographic Hardening
|
||||
All high-risk commands require an Ed25519 signature. The agent verifies the signature against the `public_key` provided in the local config. If the signature is missing or invalid, the command is rejected regardless of the capability matrix.
|
||||
|
||||
Verification is **fail-closed**: an agent with no `public_key` configured rejects
|
||||
every high-risk command. (Before protocol v1.2.0 it logged "skipping signature
|
||||
verification" and executed them, so an agent installed without a key would run
|
||||
`reboot`, `configure_ldap` and `arbitrary_bash` unverified.)
|
||||
|
||||
### Enrollment
|
||||
The agent's token must be **issued by the SSO**. The server stores only its
|
||||
SHA-256 and rejects anything else at the WebSocket handshake, so a token cannot
|
||||
be minted client-side, and an enrollment can be revoked or rotated centrally —
|
||||
either drops the agent's live connection immediately. See `PROTOCOL.md` §1.1.
|
||||
|
||||
### Capability Matrix
|
||||
|
||||
| Capability | Risk Level | Description | Impact |
|
||||
@@ -56,7 +67,7 @@ Configuration is stored in YAML format at `/etc/theta42/agent.yml`.
|
||||
### Example `agent.yml`
|
||||
```yaml
|
||||
server_url: "wss://sso.theta42.local"
|
||||
auth_token: "your-unique-host-token"
|
||||
auth_token: "issued-by-the-sso-at-enrollment"
|
||||
public_key: "base64-encoded-ed25519-public-key"
|
||||
location: "dc-01-rack-12"
|
||||
capabilities:
|
||||
@@ -71,7 +82,12 @@ capabilities:
|
||||
|
||||
1. **Build**: Compile for your target architecture (see CI/CD artifacts).
|
||||
2. **Deploy**: Place the binary in `/usr/local/bin/theta-agent`.
|
||||
3. **Configure**: Create `/etc/theta42/agent.yml` with the required token and capabilities.
|
||||
3. **Enroll**: In the SSO, open **Directory → Install Agent**, name the host, bind
|
||||
it to a host resource, and press **Enroll & issue token**. The SSO mints the
|
||||
token (shown once) and gives you its public key. Tokens the server did not
|
||||
issue are rejected.
|
||||
4. **Configure**: Create `/etc/theta42/agent.yml` with the issued `auth_token`,
|
||||
the SSO's `public_key`, and your capabilities.
|
||||
4. **Service**: Set up as a systemd unit (example: `/etc/systemd/system/theta-agent.service`).
|
||||
|
||||
For the fastest deployment, use the installation script:
|
||||
@@ -79,6 +95,14 @@ For the fastest deployment, use the installation script:
|
||||
curl -fsSL https://sso.example.com/resources/theta-agent/install.sh | sh -s -- "BASE64_ENCODED_CONFIG"
|
||||
```
|
||||
|
||||
The **Install Agent** modal generates that command for you after enrollment,
|
||||
with the token and public key already embedded. The equivalent flag form is:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://sso.example.com/resources/theta-agent/install.sh | sh -s -- \
|
||||
--url "https://sso.example.com" --token "<ISSUED_TOKEN>" --public-key "<BASE64_PUBLIC_KEY>"
|
||||
```
|
||||
|
||||
## Development & Testing
|
||||
|
||||
The agent uses a decoupled execution engine for safety and testability.
|
||||
|
||||
Reference in New Issue
Block a user