Files
ouranos/docs/kernos.md
2026-04-07 14:13:21 +00:00

272 lines
7.1 KiB
Markdown

# Kernos Service Documentation
HTTP-enabled MCP shell server using FastMCP. Wraps the existing `mcp-shell-server` execution logic with FastMCP's HTTP transport for remote AI agent access.
Kernos is Project 202.
## Features
- **HTTP Transport**: Accessible via URL instead of stdio
- **API Key Authentication**: Optional per-request authentication for MCP endpoints
- **Health Endpoints**: `/live`, `/ready`, `/health` for Kubernetes-style probes
- **Prometheus Metrics**: `/metrics` endpoint for monitoring
- **JSON Structured Logging**: Production-ready log format with correlation IDs
- **Full Security**: Command whitelisting and API key authentication
## Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/mcp/` | POST | MCP protocol endpoint (FastMCP handles this) |
| `/live` | GET | Liveness probe - always returns 200 |
| `/ready` | GET | Readiness probe - checks executor and config |
| `/health` | GET | Combined health check |
| `/metrics` | GET | Prometheus metrics (text/plain) or JSON |
## Ansible Playbooks
### Stage Playbook
```bash
ansible-playbook kernos/stage.yml
```
Fetches the Kernos repository from clio and creates a release tarball at `~/rel/kernos_{{kernos_rel}}.tar`.
### Deploy Playbook
```bash
ansible-playbook kernos/deploy.yml
```
Deploys Kernos to caliban.incus:
1. Creates kernos user/group
2. Creates `/srv/kernos` directory
3. Transfers and extracts the staged tarball
4. Creates Python virtual environment
5. Installs package dependencies
6. Templates `.env` configuration
7. Templates systemd service file
8. Enables and starts the service
9. Validates health endpoints
## Configuration Variables
### Host Variables (`ansible/inventory/host_vars/caliban.incus.yml`)
| Variable | Description |
|----------|-------------|
| `kernos_user`| System user for the service |
| `kernos_group` | System group for the service |
| `kernos_directory` | Installation directory |
| `kernos_port` | HTTP server port |
| `kernos_host` | Server bind address |
| `kernos_log_level` | Python log level |
| `kernos_log_format` | Log format (`json` or `text`) |
| `kernos_environment` | Environment name for logging |
| `kernos_allow_commands` | Comma-separated command whitelist |
| `kernos_api_keys` | Comma-separated API keys for authentication (optional) |
### Global Variables (`ansible/inventory/group_vars/all/vars.yml`)
| Variable | Default | Description |
|----------|---------|-------------|
| `kernos_rel` | `master` | Git branch/tag for staging |
## Allowed Commands
The following commands are whitelisted for execution:
```
ls, cat, head, tail, grep, find, wc, file, stat, mkdir, touch, cp, mv, rm,
chmod, pwd, tree, du, df, sed, awk, sort, uniq, cut, tr, tee, curl, wget,
ping, nc, dig, host, ps, pgrep, kill, pkill, nohup, timeout, python3, pip,
node, npm, npx, pnpm, git, make, tar, gzip, gunzip, zip, unzip, whoami, id,
uname, hostname, date, uptime, free, which, env, printenv, run-captured, jq
```
## Security
All security features are inherited from `mcp-shell-server`:
- **Command Whitelisting**: Only commands in `ALLOW_COMMANDS` can be executed
- **Shell Operator Validation**: Commands after `;`, `&&`, `||`, `|` are validated
- **Directory Validation**: Working directory must be absolute and accessible
- **No Shell Injection**: Commands executed directly without shell interpretation
The systemd service includes additional hardening:
- `NoNewPrivileges=true`
- `PrivateTmp=true`
- `ProtectSystem=strict`
- `ProtectHome=true`
- `ReadWritePaths=/tmp`
## Authentication
Kernos supports optional API key authentication. When enabled, all MCP requests (tools, resources, prompts) must include a valid key. Health and metrics endpoints (`/live`, `/ready`, `/health`, `/metrics`) remain open for probes and monitoring.
### Generating API Keys
Generate a cryptographically secure key with:
```bash
# Using openssl (recommended)
openssl rand -hex 32
# Or using Python
python3 -c "import secrets; print(secrets.token_hex(32))"
```
### Enabling Authentication
Add API keys to your host variables in `ansible/inventory/host_vars/caliban.incus.yml`:
```yaml
# Single key
kernos_api_keys: "a1b2c3d4e5f6..."
# Multiple keys (comma-separated)
kernos_api_keys: "key-for-alice,key-for-bob,key-for-ci-pipeline"
```
When `kernos_api_keys` is empty or unset, authentication is disabled (open access).
### Sending the Key
Clients authenticate via either header:
| Header | Format |
|--------|--------|
| `Authorization` | `Bearer <key>` |
| `X-Api-Key` | `<key>` |
#### FastMCP Client
```python
from fastmcp import Client
async with Client(
"http://caliban.incus:22021/mcp",
auth="your-api-key-here",
) as client:
result = await client.call_tool("shell_execute", {"command": ["ls", "-la"]})
```
#### curl
```bash
# Using Authorization header
curl -H "Authorization: Bearer your-api-key-here" http://caliban.incus:22021/mcp/
# Using X-Api-Key header
curl -H "X-Api-Key: your-api-key-here" http://caliban.incus:22021/mcp/
```
#### MCP client config (e.g. Claude Desktop, OpenAI)
```json
{
"mcpServers": {
"kernos": {
"url": "http://caliban.incus:22021/mcp/",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
}
}
}
```
## Usage
### Testing Health Endpoints
/health
/ready
/live
/metrics
### MCP Client Connection
Connect using any MCP client that supports HTTP transport:
```python
from fastmcp import Client
client = Client("http://caliban.incus:22021/mcp")
async with client:
result = await client.call_tool("shell_execute", {
"command": ["ls", "-la"],
"directory": "/tmp"
})
print(result)
```
## Tool: shell_execute
Execute a shell command in a specified directory.
### Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `command` | `list[str]` | Yes | - | Command and arguments as array |
| `directory` | `str` | No | `/tmp` | Absolute path to working directory |
| `stdin` | `str` | No | `None` | Input to pass to command |
| `timeout` | `int` | No | `None` | Timeout in seconds |
### Response
```json
{
"stdout": "command output",
"stderr": "",
"status": 0,
"execution_time": 0.123
}
```
## Monitoring
### Prometheus Metrics
The `/metrics` endpoint exposes Prometheus-compatible metrics. Add to your Prometheus configuration:
```yaml
- job_name: 'kernos'
static_configs:
- targets: ['caliban.incus:22021']
```
### Service Status
```bash
# Check service status
sudo systemctl status kernos
# View logs
sudo journalctl -u kernos -f
```
## Troubleshooting
### Service Won't Start
1. Check logs: `journalctl -u kernos -n 50`
2. Verify `.env` file exists and has correct permissions
3. Ensure Python venv was created successfully
4. Check that `ALLOW_COMMANDS` is set
### Health Check Failures
1. Verify the service is running: `systemctl status kernos`
2. Check if port is accessible
3. Review logs for startup errors
### Command Execution Denied
1. Verify the command is in `ALLOW_COMMANDS` whitelist
2. Check that the working directory is absolute and accessible
3. Review logs for security validation errors