Agent Security Model
Overview
Agents are trusted components that execute deployment tasks on targets. Their security model ensures:
- Strong identity through mTLS certificates
- Minimal privilege through scoped task credentials
- Audit trail through signed task receipts
- Isolation through process sandboxing
Agent Registration Flow
Implementation note (2026-05-09): the implemented HTTP control plane uses POST /api/v1/release-orchestrator/agents/registration-tokens for the operator-created one-time token and POST /api/v1/release-orchestrator/agents to consume that token. The local compose path is devops/compose/scripts/launch-agent-core.ps1: it reuses existing local enrollment material when present, otherwise calls the bootstrap script to create the token, register the agent, and write the issued PEM bundle to ignored local files. It then starts the agent-core service through the canonical compose chain and waits for a heartbeat. Use agent-bootstrap.ps1 -NoComposeUp or the Bash bootstrap with --no-compose-up only when another installer owns process launch. The older conceptual /api/v1/agents/register and agent JWT-token steps below are retained as product direction, not the current implemented endpoint shape. Registration is fail-closed: the internal CA must issue the client certificate before release.agents receives an active agent row, and the store writes the active row plus public certificate PEM in one operation.
┌─────────────────────────────────────────────────────────────────────────────┐
│ AGENT REGISTRATION FLOW │
│ │
│ 1. Admin generates registration token (one-time use) │
│ POST /api/v1/admin/agent-tokens │
│ Response: { token: "reg_xxx", expiresAt: "..." } │
│ │
│ 2. Agent starts with registration token │
│ ./stella-agent --register --token=reg_xxx │
│ │
│ 3. Agent requests mTLS certificate │
│ POST /api/v1/agents/register │
│ Headers: X-Registration-Token: reg_xxx │
│ Body: { name, version, capabilities, csr } │
│ Response: { agentId, certificate, caCertificate } │
│ │
│ 4. Agent establishes mTLS connection │
│ Uses issued certificate for all subsequent requests │
│ │
│ 5. Agent requests short-lived JWT for task execution │
│ POST /api/v1/agents/token (over mTLS) │
│ Response: { token, expiresIn: 3600 } │
│ │
│ 6. Agent refreshes token before expiration │
│ Token refresh only over mTLS connection │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
mTLS Communication
All agent-to-core communication uses mutual TLS:
┌─────────────────────────────────────────────────────────────────────────────┐
│ AGENT COMMUNICATION SECURITY │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ AGENT │ │ STELLA CORE │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ │ mTLS (mutual TLS) │ │
│ │ - Agent cert signed by Stella CA │ │
│ │ - Server cert verified by Agent │ │
│ │ - TLS 1.3 only │ │
│ │ - Perfect forward secrecy │ │
│ │◄────────────────────────────────────────►│ │
│ │ │ │
│ │ Encrypted payload │ │
│ │ - Task payloads encrypted with │ │
│ │ agent-specific key │ │
│ │ - Logs encrypted in transit │ │
│ │◄────────────────────────────────────────►│ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
TLS Requirements
Implementation note (2026-05-09): Release Orchestrator now owns a file-backed internal agent CA. FileBackedInternalAgentCa creates or loads the root PFX from ReleaseOrchestrator:AgentCertificateAuthority:RootPfxPath, writes an optional public root PEM to RootCertificatePemPath, and signs agent client certificates during registration. The agent-runtime HTTP endpoints receive the client certificate from the TLS layer and MtlsPollingAgentTaskTransport validates the presented certificate against that internal CA before accepting a poll or signed result. Kestrel may be configured to pass client certificates through without relying on OS trust via ReleaseOrchestrator:AgentCertificateAuthority:AllowTlsHandshakeClientCertificatePassThrough so the app-layer CA check is authoritative.
| Requirement | Value |
|---|---|
| Protocol | TLS 1.3 only |
| Cipher Suites | TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256 |
| Key Exchange | ECDHE with P-384 or X25519 |
| Certificate Key | RSA 3072-bit by default for the internal CA and issued client certs |
| Certificate Validity | 24 hours by default for issued client certs |
Certificate Management
Certificate Structure
interface AgentCertificate {
subject: {
CN: string; // Agent name
O: string; // "Stella Ops"
OU: string; // Tenant ID
};
serialNumber: string;
issuer: string; // Stella CA
validFrom: DateTime;
validTo: DateTime;
extensions: {
keyUsage: ["digitalSignature", "keyEncipherment"];
extendedKeyUsage: ["clientAuth"];
subjectAltName: string[]; // Agent ID as URI
};
}
Certificate Renewal
Agents automatically renew certificates before expiration:
- Agent detects certificate expiring within 30 days
- Agent generates new CSR with same identity
- Agent submits renewal request over existing mTLS connection
- Authority issues new certificate
- Agent transitions to new certificate seamlessly
Secrets Management
Secrets are NEVER stored in the Stella database. Only vault references are stored.
┌─────────────────────────────────────────────────────────────────────────────┐
│ SECRETS FLOW (NEVER STORED IN DB) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ VAULT │ │ STELLA CORE │ │ AGENT │ │
│ │ (Source) │ │ (Broker) │ │ (Consumer) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ │ Task requires secret │ │
│ │ │ │ │
│ │ Fetch with service │ │ │
│ │ account token │ │ │
│ │◄─────────────────────── │ │
│ │ │ │ │
│ │ Return secret │ │ │
│ │ (wrapped, short TTL) │ │ │
│ │────────────────────────► │ │
│ │ │ │ │
│ │ │ Embed in task payload │ │
│ │ │ (encrypted) │ │
│ │ │────────────────────────► │
│ │ │ │ │
│ │ │ │ Decrypt │
│ │ │ │ Use for task │
│ │ │ │ Discard │
│ │
│ Rules: │
│ - Secrets NEVER stored in Stella database │
│ - Only Vault references stored │
│ - Secrets fetched at execution time only │
│ - Secrets not logged (masked in logs) │
│ - Secrets not persisted in agent memory beyond task scope │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Task Security
Task Assignment
interface AgentTask {
id: UUID;
type: TaskType;
targetId: UUID;
payload: TaskPayload;
credentials: EncryptedCredentials; // Encrypted with agent's public key
timeout: number;
priority: TaskPriority;
idempotencyKey: string;
assignedAt: DateTime;
expiresAt: DateTime;
}
Credential Scoping
Task credentials are:
- Scoped to specific target only
- Valid only for task duration
- Encrypted with agent’s public key
- Logged when accessed (without values)
Task Execution Isolation
Agents execute tasks with isolation:
interface TaskExecutionContext {
// Process isolation
workingDirectory: string; // Unique per task
processUser: string; // Non-root user
networkNamespace: string; // If network isolation enabled
// Resource limits
memoryLimit: number; // Bytes
cpuLimit: number; // Millicores
diskLimit: number; // Bytes
networkEgress: string[]; // Allowed destinations
// Cleanup
cleanupOnComplete: boolean;
cleanupTimeout: number;
}
Agent Capabilities
Agents declare capabilities that determine what tasks they can execute:
interface AgentCapabilities {
docker?: DockerCapability;
compose?: ComposeCapability;
ssh?: SshCapability;
winrm?: WinrmCapability;
ecs?: EcsCapability;
nomad?: NomadCapability;
}
interface DockerCapability {
version: string;
apiVersion: string;
runtimes: string[];
registryAuth: boolean;
}
interface ComposeCapability {
version: string;
fileFormats: string[];
}
Heartbeat Protocol
interface AgentHeartbeat {
agentId: UUID;
timestamp: DateTime;
status: "healthy" | "degraded";
resourceUsage: {
cpuPercent: number;
memoryPercent: number;
diskPercent: number;
networkRxBytes: number;
networkTxBytes: number;
};
activeTaskCount: number;
completedTasks: number;
failedTasks: number;
errors: string[];
signature: string; // HMAC of heartbeat data
}
Heartbeat Validation
- Verify signature matches expected HMAC
- Check timestamp is within acceptable skew (30s)
- Update agent status based on heartbeat content
- Trigger alerts if heartbeat missing for >90s
Agent Revocation
When an agent is compromised or decommissioned:
- Certificate added to CRL (Certificate Revocation List)
- All pending tasks for agent cancelled
- Agent removed from target assignments
- Audit event logged
- New agent can be registered with same name (new identity)
Security Checklist
| Control | Implementation |
|---|---|
| Identity | mTLS certificates signed by internal CA |
| Authentication | Certificate-based + short-lived JWT |
| Authorization | Task-scoped credentials |
| Encryption | TLS 1.3 for transport, envelope encryption for secrets |
| Isolation | Process sandboxing, resource limits |
| Audit | All task assignments and completions logged |
| Revocation | CRL for compromised agents |
| Secret handling | Vault integration, no persistence |
