System Design: Engagement Planning & Artifact Management Platform
1. Problem Statement
Design an internal platform for a red team consulting firm to manage engagement lifecycle: from scoping through authorization, execution, artifact management, deconfliction, and final reporting. The platform serves a team of 15–30 consultants running 10–20 concurrent engagements.
Functional requirements:
- Engagement CRUD: create engagement, associate client, define scope, set dates
- ROE document generation and signature tracking
- Deconfliction log: timestamped log of operator actions for each engagement
- Artifact vault: encrypted storage for engagement artifacts (screenshots, credential proofs, network captures); per-engagement access control
- Report drafting: collaborative finding management (create/assign/review findings)
- ATT&CK mapping: each finding links to one or more ATT&CK technique IDs
- Status dashboard: engagement status, upcoming deadlines, finding counts by severity
Non-functional requirements:
- Multi-tenant: findings and artifacts from one client never visible to another
- Encryption: artifacts encrypted at rest; keys managed per engagement
- Audit log: all access to artifacts and report drafts logged immutably
- Availability: 99.9% uptime during active engagement windows (not 24/7 but business-hours-critical)
- Access control: role-based (operator, engagement lead, partner/reviewer, admin)
2. Constraints
In scope:
- Engagement and finding data model
- Access control model
- Artifact storage design
- Deconfliction log design
- API surface for operator tooling integration
Out of scope:
- C2 infrastructure (covered in Design 01)
- Client-facing portal
- Automated exploitation tooling
3. High-Level Architecture
┌──────────────────────────────────────────────────────────────────────────┐
│ Web/CLI Clients (consultants, engagement leads, partners) │
└───────────────────────────────┬──────────────────────────────────────────┘
│ HTTPS + mTLS (internal PKI)
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ API Gateway / Auth Layer │
│ - Authenticate: OIDC SSO (internal IdP) │
│ - Authorize: role-based access control per engagement │
│ - Rate-limit: prevent bulk artifact download │
└───────────────────────────────┬──────────────────────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌────────────────────┐ ┌───────────────────┐
│ Engagement │ │ Finding & Report │ │ Artifact Vault │
│ Service │ │ Service │ │ Service │
│ - CRUD │ │ - Finding CRUD │ │ - Encrypted blob │
│ - ROE gen │ │ - ATT&CK mapping │ │ store │
│ - Scope mgmt│ │ - Collab drafting │ │ - Per-engagement │
│ - Timeline │ │ - Severity/review │ │ KMS key │
└──────┬───────┘ └────────┬───────────┘ └────────┬──────────┘
│ │ │
└────────────────────┼────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Shared: Deconfliction Log Service │
│ - Append-only timestamped records │
│ - Per-engagement access │
│ - Immutable audit trail │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Persistence Layer │
│ PostgreSQL: structured data │
│ S3: artifact blobs (server-side │
│ AES-256 + client-side key) │
└─────────────────────────────────────┘
4. Component Deep-Dives
4.1 Engagement Data Model
-- Core engagement table
CREATE TABLE engagements (
id UUID PRIMARY KEY,
client_name TEXT NOT NULL,
code_name TEXT NOT NULL, -- e.g., "Cedar Lattice"
start_date DATE NOT NULL,
end_date DATE NOT NULL,
status TEXT NOT NULL, -- planning | active | completed | archived
kms_key_id TEXT NOT NULL, -- per-engagement encryption key ARN
created_by UUID NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Scope definition (IP ranges, domains, cloud accounts)
CREATE TABLE scope_entries (
id UUID PRIMARY KEY,
engagement_id UUID REFERENCES engagements(id),
entry_type TEXT NOT NULL, -- in_scope | out_of_scope
description TEXT NOT NULL,
value TEXT NOT NULL, -- IP range, domain, AWS account ID, etc.
);
-- ROE document tracking
CREATE TABLE roe_documents (
id UUID PRIMARY KEY,
engagement_id UUID REFERENCES engagements(id),
version INT NOT NULL,
content_hash TEXT NOT NULL, -- SHA-256 of the signed document
signed_by_name TEXT NOT NULL, -- client authority
signed_at TIMESTAMPTZ,
status TEXT NOT NULL, -- draft | pending_signature | signed
);
4.2 Access Control Model
Roles (per engagement, not global):
| Role | What they can do |
|---|---|
operator | Read engagement scope and ROE; write to deconfliction log; upload artifacts to engagement vault; create findings (draft only) |
engagement_lead | All operator permissions + promote findings to review; edit scope; add operators; generate report draft |
partner_reviewer | Read-only for report review; can leave comments; can approve final report |
admin | Full access; cross-engagement visibility; manage encryption keys |
Implementation: RBAC with engagement-scoped roles. A user can be an operator on one
engagement and an engagement_lead on another simultaneously. Access check:
(user_id, engagement_id, role) tuple lookup before every operation.
Key principle: no cross-engagement data access for non-admin roles. An operator on
Cedar Lattice cannot list engagements or access artifacts from another engagement.
4.3 Artifact Vault
Security requirement: finding artifacts (screenshots of credential captures, network traffic extracts) are client-sensitive. If the platform is compromised, artifacts must not be readable without the engagement key.
Encryption model:
- Each engagement has a unique KMS Customer Managed Key (CMK), created at engagement start
- Artifacts are encrypted client-side (before upload) with the CMK
- S3 stores only encrypted blobs
- The CMK is accessible only to users with the
operatoror higher role on that engagement - At engagement archive (30 days post-end), the CMK is disabled; artifacts become unreadable without an admin CMK re-enable
Upload flow:
Operator → API: upload artifact
API: verify operator role on engagement
API: request data key from KMS (CMK for engagement)
API: encrypt artifact blob client-side with data key
API: store encrypted blob in S3, metadata (name, type, uploader, timestamp) in Postgres
API: return artifact ID to operator
KMS: log key usage to CloudTrail
Download flow (same in reverse):
Operator → API: download artifact ID
API: verify operator role on engagement
API: fetch encrypted blob from S3
API: decrypt data key via KMS (CMK for engagement)
API: decrypt blob, return to operator
KMS: log key usage
4.4 Deconfliction Log Service
Requirement: an immutable record of operator actions, used during deconfliction calls and for the engagement report's activity timeline.
Design:
- PostgreSQL table with append-only INSERT permissions (no UPDATE, no DELETE via application role)
- A separate read-only role for generating the deconfliction report
- Fields:
{id, engagement_id, operator_id, timestamp_utc, action_type, target_host, description, session_id} action_type: enum of{scan, exploit, credential_dump, lateral_move, persistence, collection, tool_deploy, cleanup, deconfliction_stop, deconfliction_resume}
API: POST /engagements/{id}/deconfliction-log (operator writes an entry)
GET /engagements/{id}/deconfliction-log?from=T&to=T (lead/partner reads the timeline)
Immutability guarantee: the application service role has INSERT only on the
deconfliction_log table. UPDATE and DELETE are granted only to the admin role,
which requires a separate authentication factor and generates a high-priority audit event.
4.5 Finding and Report Service
Finding state machine:
draft → under_review → approved → published
↑ ↓
└── rejected ┘
Each finding in draft contains: title, severity, attck_id, precondition, evidence references (artifact vault IDs), detection opportunity, remediation, residual risk.
Collaborative editing: findings are individually locked during edit (optimistic lock with a 5-minute TTL). Last-write-wins within the lock window.
Report generation: the report generator pulls all approved findings, sorts by severity, and renders the Mandiant-style report structure: executive summary (auto-drafted from finding count and severity distribution), engagement overview, finding details, detection-gap matrix, remediation roadmap.
5. Tradeoffs
Monolith vs. microservices:
- The five services (engagement, finding, artifact, deconfliction, auth) could be separate microservices. For a 15–30 person firm with 10–20 concurrent engagements, the scale does not justify microservice operational overhead.
- Decision: modular monolith with clear service boundaries in code; can extract to microservices if the firm scales past 100 concurrent engagements.
PostgreSQL vs. document store for findings:
- Findings have a flexible schema (fields added as methodology evolves). A document store (MongoDB, DynamoDB) handles schema evolution better.
- But the engagement and user relationships require relational integrity (a finding belongs to one engagement, enforced by FK).
- Decision: PostgreSQL with JSONB for the flexible
finding_metadatafield; relational tables for the fixed schema entities.
Client-side encryption vs. server-side:
- Server-side encryption (SSE-S3, SSE-KMS) encrypts at rest but decrypts transparently on read — if the platform is compromised, artifacts are readable.
- Client-side encryption means the platform itself never holds plaintext; compromise of the platform server does not expose artifact content.
- Decision: client-side encryption (more secure, acceptable UX for a professional tool).
6. Detection-Forward Perspective
This platform is an internal defensive control for the red team firm itself:
- The artifact vault's CMK audit trail in CloudTrail is the firm's own detection mechanism: if a CMK is used outside of business hours or by an unexpected user, that is an internal security alert.
- The deconfliction log serves as the firm's own audit trail for legal protection.
- The immutable finding state machine prevents retroactive modification of reported findings (important for professional integrity and potential legal scrutiny).
From an external attacker's perspective, this platform is a high-value target: it contains client credentials and vulnerability proof artifacts. The CMK-based artifact encryption and per-engagement key rotation are the primary data-loss mitigations.