Skip to content

Architecture Overview

Maks Zaikin edited this page Jun 26, 2026 · 1 revision

title: "Architecture Overview" category: "architecture" version: "1.0" last_updated: "2024-01-15" standards: ["NIST-SP-800-53", "ISA-IEC-62443", "FSTEC"] related_pages: ["Architecture-Data-Fragmentation", "Architecture-Encryption-Model", "Architecture-Network-Topology", "Architecture-Container-Architecture", "Architecture-Message-Bus", "Security-Principles"] ai_summary: "Complete VaultFlower system architecture. Three-database data fragmentation, HashiCorp Vault as trust anchor, RabbitMQ async messaging, plugin-based MFA, and ISA/IEC 62443 asset hierarchy."

🏗️ Architecture Overview

The Core Problem

Classical PAM solutions solve privileged access for domain-joined, network-connected assets. VaultFlower solves the harder problem: privileged access for assets that cannot be reached by classical PAM. plus it ads an integrity management workflow for transparency and controll


Classical PAM covers:                 VaultFlower additionally covers:
✅ Domain-joined Windows servers     ✅ Air-gapped OT networks
✅ Network-connected Linux hosts     ✅ Offline/isolated assets
✅ Cloud infrastructure              ✅ Non-domain ICS/SCADA systems
                                     ✅ Legacy industrial controllers
                                     ✅ Break-glass accounts

Fundamental Design Principles

Every architectural decision in VaultFlower derives from these principles. They are non-negotiable and take precedence over convenience, performance, or simplicity.

principles:
  - id: P1
    name: "Data Fragmentation"
    statement: >
      No single component ever has access to the complete data picture
      without explicit authorization through HashiCorp Vault.
    standard: "NIST SP 800-53 AC-3, AC-4"

  - id: P2
    name: "Zero Persistence of Plaintext"
    statement: >
      Plaintext passwords exist only in application memory during assembly.
      They are shown once in the UI and immediately destroyed.
    standard: "NIST SP 800-53 SC-28, IA-5"

  - id: P3
    name: "Dual Control"
    statement: >
      Every password access requires two independent MFA authorizations
      from two different users. No bypass exists for any role.
    standard: "NIST SP 800-53 AC-3(2), FSTEC ОПС.1"

  - id: P4
    name: "Immutable Audit"
    statement: >
      Audit log tables have INSERT-only database grants.
      UPDATE and DELETE are never permitted on audit schemas.
    standard: "NIST SP 800-53 AU-9, AU-10"

  - id: P5
    name: "Async Messaging"
    statement: >
      No direct HTTP between internal services.
      All inter-service communication goes through RabbitMQ with mTLS.
    standard: "Defense in depth"

  - id: P6
    name: "Task-Gated Access"
    statement: >
      Any password access requires an active work task approved
      by the system owner. No task = no access.
    standard: "NIST SP 800-53 AC-2, FSTEC УПД.1"

System Components

Component Map


┌────────────────────────────────────────────────────────────────┐
│  EXTERNAL                                                      │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐                  │
│  │ Browser  │    │  AD/DNS  │    │  PKI/CA  │                  │
│  │(Operator │    │  DC02    │    │  ICA01   │                  │
│  │ Admin    │    │.115      │    │  .51     │                  │
│  │ Auditor) │    └──────────┘    └──────────┘                  │
│  └────┬─────┘         │               │                        │
│       │ HTTPS:443     │ Kerberos      │ TLS Certs              │
└───────│───────────────│───────────────│────────────────────────┘
        │               │               │
┌───────│───────────────│───────────────│─────────────────────────┐
│  vfw-core (.210)      |               │                         │
│       │               │               │                         │
│  ┌────▼─────┐         │               │                         │
│  │ nginx    │◄────────┘               │                         │
│  │ :443     │         TLS termination │                         │
│  └────┬─────┘                         │                         │
│       │                               │                         │
│  ┌────▼──────┐    ┌──────────────┐    │                         │
│  │ Blazor    │    │ .NET 9       │    │                         │
│  │ Server    │    │ Minimal API  │    │                         │
│  │ Portal    │    │ :7001        │    │                         │
│  └────┬──────┘    └──────┬───────┘    │                         │
│       │                  │            │                         │
│       └──────────┬───────┘            │                         │
│                  │                    │                         │
│           ┌──────▼──────┐             │                         │
│           │  RabbitMQ   │◄────────────┘                         │
│           │  mTLS :5671 │             mTLS certs from PKI       │
│           └──────┬──────┘                                       │
│                  │                                              │
│     ┌────────────┼────────────┐                                 │
│     │            │            │                                 │
│  ┌──▼───┐   ┌───▼───┐   ┌───▼──────────┐                        │
│  │Worker│   │Vault  │   │ PostgreSQL   │                        │
│  │Work- │   │:8200  │   │ 3 databases  │                        │
│  │flow  │   │(KMS)  │   │ :5432/:5433  │                        │
│  └──────┘   └───────┘   │ /:5434       │                        │
│                         └──────────────┘                        │
│                                                                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐         │
│  │ Consul   │  │ MinIO    │  │ OTel     │  │ Grafana  │         │
│  │ :8500    │  │ :9000    │  │ Collector│  │ :3000    │         │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘         │
└─────────────────────────────────────────────────────────────────┘
              │ AMQPS:5671 (mTLS)
┌─────────────│────────────────────────────────────────────────────┐
│  APP01 (.125)                                                    │
│             │                                                    │
│  ┌──────────▼──────────────────────────────────────────────┐     │
│  │  VaultFlower.Worker.Rotation (Windows Service + gMSA)   │     │
│  │  Executors: WinRM / SSH / LDAP                          │     │
│  └──────────┬──────────────────────────────────────────────┘     │
└─────────────│────────────────────────────────────────────────────┘
              │ WinRM/SSH/LDAP
┌─────────────▼────────────────┐
│  Target Assets               │
│  vfw-pki (.51)               │
│  + production assets         │
└──────────────────────────────┘

Component Responsibilities

Component Technology Responsibility
vfw-dc-nginx nginx:alpine TLS termination, reverse proxy
vfw-dc-portal Blazor Server .NET 9 Admin UI, operator UI, auditor UI
vfw-dc-api ASP.NET Core Minimal API .NET 9 REST API, JWT auth, business logic
vfw-dc-worker-workflow .NET 9 Worker Checkout/checkin state machine, rotation scheduling
vfw-dc-rabbitmq RabbitMQ 4 Async messaging between all services (mTLS)
vfw-dc-vault HashiCorp Vault OSS KMS, DEK storage, assembly tokens, Shamir unseal
vfw-dc-consul HashiCorp Consul Service discovery, active health checks
vfw-dc-postgres-assets PostgreSQL 17 Assets DB: locations, systems, zones, assets, tasks
vfw-dc-postgres-secrets PostgreSQL 17 Secrets DB: encrypted credentials, checkouts, history
vfw-dc-postgres-identity PostgreSQL 17 Identity DB: users, roles, MFA, tenants
vfw-dc-minio MinIO Object storage for signed task completion forms
vfw-dc-otel OpenTelemetry Collector Traces, metrics collection + PII masking
vfw-dc-jaeger Jaeger Distributed tracing UI
vfw-dc-victoria VictoriaMetrics Metrics storage and querying
vfw-dc-grafana Grafana Dashboards and alerting
vfw-dc-registry Docker Registry Private container image registry
VaultFlower.Worker.Rotation .NET 9 Windows Service Rotation execution: WinRM, SSH, LDAP
VaultFlower.Agent.Workstation .NET 9 Windows Service Smartcard reader on operator workstations

Asset Hierarchy

VaultFlower organizes managed assets according to the ISA/IEC 62443 Zones and Conduits model:


Tenant (Organization)
└── Location (Physical site / plant)
    └── System (Functional system with owner and criticality)
        └── Zone (Network segment: OT domain, IT domain, air-gapped)
            └── Asset (Server, HMI, PLC, RTU, workstation)
                └── Credential (Local admin, domain account, service account)

Criticality Levels

Per ISA/IEC 62443 and NERC CIP, each system is assigned a criticality level based on potential damage:

Level Code Damage Type Description
Low LOW Any Minimal damage, rapid recovery
Medium MEDIUM Any Limited damage, partial production loss
High HIGH Any Significant damage, extended downtime
Critical CRITICAL ECONOMIC / ENVIRONMENTAL / HUMAN / COMBINED Catastrophic damage, threat to life or environment

Criticality directly affects the authentication model:

  • LOW / MEDIUM / HIGH → Kerberos SSO + Password MFA
  • CRITICAL → Kerberos SSO + Password MFA + Smartcard + PIN (3FA)

Data Flow — Password Checkout

The most critical flow in the system. Every step is audited.

1. Operator creates ACCESS_TASK or ROTATION_TASK
         │
         ▼
2. System emails owner with SSO-gated one-time approval link (TTL: 12h)
         │
         ▼
3. Owner opens link → Kerberos SSO validates identity
   Match → approval page
   No match → 403 + CRITICAL SIEM event
         │
         ▼
4. Owner approves → task status: ASSIGNED
         │
         ▼
5. Operator opens task → initiates checkout
         │
         ▼
6. Operator passes MFA (adaptive based on criticality)
         │
         ▼
7. Second approver passes MFA → Dual Control complete
         │
         ▼
8. HashiCorp Vault issues time-bound assembly token (TTL = checkout TTL)
         │
         ▼
9. Application assembles data IN MEMORY:
   Identity DB  → user context, permissions
   Assets DB    → asset details, task context
   Secrets DB   → encrypted credential
   Vault        → DEK to decrypt credential
         │
         ▼
10. Plaintext password shown ONCE in UI
    Printed form generated (mandatory)
         │
         ▼
11. Vault assembly token invalidated after use
         │
         ▼
12. Operator executes task → uploads signed form
         │
         ▼
13. Task completed → auto-rotation task created (for ACCESS_TASK)
         │
         ▼
14. All 14 steps logged to audit with CEF format → SIEM

Authentication Model

VaultFlower uses adaptive multi-factor authentication — the number of required factors scales with asset criticality:

Factor 1 (always):    Kerberos SSO — Windows AD authenticates the user
Factor 2 (always):    Password — VaultFlower internal password
Factor 3 (CRITICAL):  Smartcard (Mifare) + PIN — physical possession proof

MFA Plugin Architecture

Core MFA (Password) is built-in. Additional factors are delivered as optional Docker containers activated via Service Discovery:

Docker container starts
    │
    ▼
Plugin registers with Consul (health checks every 10s)
    │
    ▼
Plugin publishes to RabbitMQ: vfw.plugins.registry
    │
    ▼
Worker validates license via Vault
    │
    ▼
API activates plugin endpoints automatically

Available plugins: vfw-dc-mfa-totp, vfw-dc-mfa-webauthn, vfw-dc-mfa-smartcard


Encryption Architecture

Password at rest:
  plaintext → AES-256-GCM(DEK) → ciphertext stored in Secrets DB
  DEK → AES-256(KEK) → encrypted DEK stored in Vault
  KEK → Vault master key (Shamir 3-of-5) → never leaves Vault

Password in transit:
  All connections TLS 1.3 minimum
  RabbitMQ: mTLS (mutual TLS) — client and server certificates
  Certificates issued by vfw-pki (ICA01)

Password in memory:
  Assembled only during checkout flow
  Destroyed immediately after display
  Never appears in logs, traces, or metrics (PII masking at OTel level)

Full encryption details → Architecture-Encryption-Model


Multi-Tenancy

VaultFlower supports multiple organizations (tenants) on a single installation:

Tenant isolation:
  ✓ Every table has tenant_id column
  ✓ API enforces tenant context via URL prefix /{tenant-slug}/
  ✓ RabbitMQ: dedicated VHost per tenant (/vfw-tenant-{slug})
  ✓ MinIO: dedicated bucket path per tenant
  ✓ Audit log: all events tagged with tenant_id
  ✗ Shared infrastructure (PostgreSQL instances, Vault, RabbitMQ)
    — isolation is logical, not physical

For physical tenant isolation (separate DB instances per tenant), see Enterprise edition.


Observability

Application → OpenTelemetry SDK
    │
    ▼
vfw-dc-otel (OpenTelemetry Collector)
    │
    ├── PII Masking (before export):
    │   User UPN → masked
    │   IP addresses → masked
    │   Tenant slug → preserved (not PII)
    │
    ├──→ vfw-dc-jaeger (Distributed Tracing)
    │    X-Request-ID links traces to audit log entries
    │
    └──→ vfw-dc-victoria (Metrics)
         └──→ vfw-dc-grafana (Dashboards + Alerts)

Technology Decisions Summary

Decision Choice Alternative Considered Reason
Inter-service communication RabbitMQ HTTP/REST Durability, async, mTLS
Secret management HashiCorp Vault AWS KMS Self-hosted, air-gap compatible
Service discovery Consul Kubernetes DNS Active health checks, multi-DC
Object storage MinIO PostgreSQL bytea S3-compatible, versioned, encrypted
Portal technology Blazor Server React/Vue Logic never leaves server
Database per concern 3x PostgreSQL Single DB Data fragmentation security model
Message format CEF JSON SIEM compatibility standard

Full rationale for each decision → ADR section


Related Pages

Clone this wiki locally