# Orchestrator Security Documentation

## Overview

This document outlines the security measures implemented in the Mosaic Orchestrator Docker container and deployment configuration.

## Docker Security Hardening

### Multi-Stage Build

The Dockerfile uses a **4-stage build process** to minimize attack surface:

1. **Base Stage**: Minimal Alpine base with pnpm enabled
2. **Dependencies Stage**: Installs production dependencies only
3. **Builder Stage**: Builds the application with all dependencies
4. **Runtime Stage**: Final minimal image with only built artifacts

**Benefits:**

- Reduces final image size by excluding build tools and dev dependencies
- Minimizes attack surface by removing unnecessary packages
- Separates build-time from runtime environments

### Base Image Security

**Image:** `node:20-alpine`

**Security Scan Results** (Trivy, 2026-02-02):

- Alpine Linux: **0 vulnerabilities**
- Node.js packages: **0 vulnerabilities**
- Base image size: ~180MB (vs 1GB+ for full node images)

**Why Alpine?**

- Minimal attack surface (only essential packages)
- Security-focused distribution
- Regular security updates
- Small image size reduces download time and storage

### Non-Root User

**User:** `node` (UID: 1000, GID: 1000)

The container runs as a non-root user to prevent privilege escalation attacks.

**Implementation:**

```dockerfile
# Dockerfile
USER node

# docker-compose.yml
user: "1000:1000"
```

**Security Benefits:**

- Prevents root access if container is compromised
- Limits blast radius of potential vulnerabilities
- Follows principle of least privilege

### File Permissions

All application files are owned by `node:node`:

```dockerfile
COPY --from=builder --chown=node:node /app/apps/orchestrator/dist ./dist
COPY --from=dependencies --chown=node:node /app/node_modules ./node_modules
```

**Permissions:**

- Application code: Read/execute only
- Workspace volume: Read/write (required for git operations)
- Docker socket: Read-only mount

### Health Checks

**Dockerfile Health Check:**

```dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
```

**Benefits:**

- Container orchestration can detect unhealthy containers
- Automatic restart on health check failure
- Minimal overhead (uses wget already in Alpine)

**Endpoint:** `GET /health`

- Returns 200 OK when service is healthy
- No authentication required (internal endpoint)

### Capability Management

**docker-compose.yml:**

```yaml
cap_drop:
  - ALL
cap_add:
  - NET_BIND_SERVICE
```

**Dropped Capabilities:**

- ALL (start with zero privileges)

**Added Capabilities:**

- NET_BIND_SERVICE (required to bind to port 3001)

**Why minimal capabilities?**

- Reduces attack surface
- Prevents privilege escalation
- Limits kernel access

### Read-Only Docker Socket

The Docker socket is mounted **read-only** where possible:

```yaml
volumes:
  - /var/run/docker.sock:/var/run/docker.sock:ro
```

**Note:** The orchestrator needs Docker access to spawn agent containers. This is intentional and required for functionality.

**Mitigation:**

- Non-root user limits socket abuse
- Capability restrictions prevent escalation
- Monitoring and killswitch can detect anomalies

### Temporary Filesystem

A tmpfs mount is configured for `/tmp`:

```yaml
tmpfs:
  - /tmp:noexec,nosuid,size=100m
```

**Security Benefits:**

- `noexec`: Prevents execution of binaries from /tmp
- `nosuid`: Ignores setuid/setgid bits
- Size limit: Prevents DoS via disk exhaustion

### Security Options

```yaml
security_opt:
  - no-new-privileges:true
```

**no-new-privileges:**

- Prevents processes from gaining new privileges
- Blocks setuid/setgid binaries
- Prevents privilege escalation

### Network Isolation

**Network:** `mosaic-internal` (bridge network)

The orchestrator is **not exposed** to the public network. It communicates only with:

- Valkey (internal)
- API (internal)
- Docker daemon (local socket)

### Labels and Metadata

The container includes comprehensive labels for tracking and compliance:

```dockerfile
LABEL org.opencontainers.image.source="https://git.mosaicstack.dev/mosaic/stack"
LABEL org.opencontainers.image.vendor="Mosaic Stack"
LABEL com.mosaic.security=hardened
LABEL com.mosaic.security.non-root=true
```

## Runtime Security

### Environment Variables

Sensitive configuration is passed via environment variables:

- `AI_PROVIDER`: Orchestrator LLM provider
- `CLAUDE_API_KEY`: Claude credentials (required only for `AI_PROVIDER=claude`)
- `VALKEY_URL`: Cache connection string

**Best Practices:**

- Never commit secrets to git
- Use `.env` files for local development
- Use secrets management (Vault) in production

### Volume Security

**Workspace Volume:**

```yaml
orchestrator_workspace:/workspace
```

**Security Considerations:**

- Persistent storage for git operations
- Writable by node user
- Isolated from other services
- Regular cleanup via lifecycle management

### Monitoring and Logging

The orchestrator logs all operations for audit trails:

- Agent spawning/termination
- Quality gate results
- Git operations
- Killswitch activations

**Log Security:**

- Secrets are redacted from logs
- Logs stored in Docker volumes
- Rotation configured to prevent disk exhaustion

## Security Checklist

- [x] Multi-stage Docker build
- [x] Non-root user (node:node, UID 1000)
- [x] Minimal base image (node:20-alpine)
- [x] No unnecessary packages
- [x] Health check in Dockerfile
- [x] Security scan passes (0 vulnerabilities)
- [x] Capability restrictions (drop ALL, add minimal)
- [x] No new privileges flag
- [x] Read-only mounts where possible
- [x] Tmpfs with noexec/nosuid
- [x] Network isolation
- [x] Comprehensive labels
- [x] Environment-based secrets

## Known Limitations

### Docker Socket Access

The orchestrator requires access to the Docker socket (`/var/run/docker.sock`) to spawn agent containers.

**Risk:**

- Docker socket access provides root-equivalent privileges
- Compromised orchestrator could spawn malicious containers

**Mitigations:**

1. **Non-root user**: Limits socket abuse
2. **Capability restrictions**: Prevents privilege escalation
3. **Killswitch**: Emergency stop for all agents
4. **Monitoring**: Audit logs track all Docker operations
5. **Network isolation**: Orchestrator not exposed publicly

**Future Improvements:**

- Consider Docker-in-Docker (DinD) for better isolation
- Implement Docker socket proxy with ACLs
- Evaluate Kubernetes pod security policies

### Workspace Writes

The workspace volume must be writable for git operations.

**Risk:**

- Code execution via malicious git hooks
- Data exfiltration via commit/push

**Mitigations:**

1. **Isolated volume**: Workspace not shared with other services
2. **Non-root user**: Limits blast radius
3. **Quality gates**: Code review before commit
4. **Secret scanning**: git-secrets prevents credential leaks

## Compliance

This security configuration aligns with:

- **CIS Docker Benchmark**: Passes all applicable controls
- **OWASP Container Security**: Follows best practices
- **NIST SP 800-190**: Application Container Security Guide

## Security Audits

**Last Security Scan:** 2026-02-02
**Tool:** Trivy v0.69
**Results:** 0 vulnerabilities (HIGH/CRITICAL)

**Recommended Scan Frequency:**

- Weekly automated scans
- On-demand before production deployments
- After base image updates

## Reporting Security Issues

If you discover a security vulnerability, please report it to:

- **Email:** security@mosaicstack.dev
- **Issue Tracker:** Use the "security" label (private issues only)

**Do NOT:**

- Open public issues for security vulnerabilities
- Disclose vulnerabilities before patch is available

## References

- [Docker Security Best Practices](https://docs.docker.com/engine/security/)
- [CIS Docker Benchmark](https://www.cisecurity.org/benchmark/docker)
- [OWASP Container Security](https://owasp.org/www-project-docker-top-10/)
- [Alpine Linux Security](https://alpinelinux.org/about/)

---

**Document Version:** 1.0
**Last Updated:** 2026-02-02
**Maintained By:** Mosaic Security Team
