Architecture Overview¶
OWASP Amass implements an event-driven plugin architecture centered on a core engine that processes asset discovery through sophisticated coordination mechanisms. The system implements the Open Asset Model (OAM) to standardize cyber asset representation across a graph database backend.
System Architecture¶
Core Components¶
Engine Core¶
The central AmassEngine orchestrates discovery operations through these key subsystems:
| Component | Purpose |
|---|---|
| Dispatcher | Routes events through registered handler pipelines, processing assets sequentially based on type and priority |
| Registry | Manages plugin registration and constructs processing pipelines dynamically |
| SessionManager | Coordinates concurrent discovery sessions with isolated state, configuration, and caching |
| GraphQL Server | Exposes endpoints for session management and real-time monitoring |
Event Processing Pipeline¶
Events flow through a deterministic pipeline where the system maintains session context including cache, queue, and scope definitions throughout processing.
sequenceDiagram
participant Client
participant GraphQL
participant Dispatcher
participant Registry
participant Handler
participant Database
Client->>GraphQL: Create Session
GraphQL->>Dispatcher: Initialize
Client->>GraphQL: Submit Asset
GraphQL->>Dispatcher: Asset Discovery Event
Dispatcher->>Registry: Get Handler Pipeline
Registry-->>Dispatcher: Ordered Handlers
loop For Each Handler
Dispatcher->>Handler: Process Event
Handler->>Handler: Execute Callback
Handler-->>Dispatcher: New Assets
end
Dispatcher->>Database: Store Results
Database-->>Client: Updated Graph
Session Management¶
The SessionManager coordinates multiple concurrent discovery sessions with isolated configuration and state:
| Component | Description |
|---|---|
session.db |
SQLite persistent storage for the session |
session.cache |
In-memory asset cache for deduplication |
session.queue |
Processing queue managing asset flow |
session.ranger |
CIDR range matching for network scope |
Multi-Layer Storage Architecture¶
Database Support¶
| Backend | Use Case |
|---|---|
| SQLite | Local, single-user deployments |
| PostgreSQL | Enterprise concurrent access |
Queue Management¶
The session queue uses SQLite with an Element table tracking processing state:
stateDiagram-v2
[*] --> Pending: Asset Discovered
Pending --> Processing: Dequeued
Processing --> Completed: Handler Done
Completed --> [*]: Removed
| Field | Purpose |
|---|---|
entity_id |
Unique asset identifier |
etype |
Asset type (FQDN, IP, etc.) |
processed |
Processing state flag |
created_at |
Queue entry timestamp |
GraphQL API Interface¶
The engine exposes a GraphQL API for programmatic control:
Mutations¶
| Operation | Description |
|---|---|
createSessionFromJson |
Initiate discovery sessions with configuration |
createAsset |
Submit seed assets for discovery |
terminateSession |
Stop running enumeration |
Queries¶
| Operation | Description |
|---|---|
sessionStats |
Real-time discovery statistics |
Subscriptions¶
| Operation | Description |
|---|---|
logMessages |
Stream session log messages |
Default endpoint: http://127.0.0.1:4000/graphql
Configuration Priority¶
Settings are resolved in priority order:
External Service Integration¶
DNS Resolution Infrastructure¶
The system manages multiple resolver pools with sophisticated rate limiting:
| Resolver Type | Description | Default QPS |
|---|---|---|
| Baseline | Google, Cloudflare, Quad9 | 15 |
| Public Pool | Dynamic from public-dns.info | 5 |
| Custom | User-specified resolvers | Configurable |
| Trusted | Higher rate limit resolvers | 15+ |
DNS Operations¶
- Wildcard detection and filtering
- QPS rate limiting per resolver
- TTL-based response caching
- Response validation
Technical Reference¶
The following diagrams provide deeper insight into Amass internals, sourced from the codebase analysis.
Detailed Component Map¶
graph TB
subgraph "User Interface Layer"
MainCLI["cmd/amass/main.go<br/>Main CLI Entry Point"]
EnumCmd["internal/enum<br/>Enum Client"]
EngineCmd["internal/amass_engine<br/>Engine Server"]
OAMTools["OAM Analysis Tools<br/>assoc, subs, track, viz"]
end
subgraph "Core Engine - engine/"
Dispatcher["dispatcher.Dispatcher<br/>dispatcher/dispatcher.go"]
SessionMgr["sessions.Manager<br/>sessions/manager.go"]
Registry["registry.Registry<br/>registry/registry.go"]
GraphQLAPI["api/graphql/server<br/>GraphQL API"]
end
subgraph "Plugin System"
PluginInterface["types.Plugin interface<br/>types/registry.go"]
HandlerRegistry["Handler Registration<br/>priority 1-9"]
AssetPipelines["AssetPipeline<br/>types/registry.go"]
end
subgraph "Session Layer - engine/sessions/"
Session["Session struct<br/>session.go"]
SessionQueue["sessionQueue<br/>queue.go"]
QueueDB["queuedb.QueueDB<br/>queuedb/queue_db.go"]
end
subgraph "Data Layer"
Cache["cache.Cache<br/>asset-db/cache"]
Repository["repository.Repository<br/>asset-db/repository"]
SQLiteQueue["SQLite Queue DB<br/>queue.db"]
end
MainCLI --> EnumCmd
MainCLI --> EngineCmd
MainCLI --> OAMTools
EnumCmd --> GraphQLAPI
GraphQLAPI --> SessionMgr
GraphQLAPI --> Dispatcher
EngineCmd --> SessionMgr
EngineCmd --> Dispatcher
EngineCmd --> Registry
Dispatcher --> SessionMgr
Dispatcher --> Registry
Registry --> PluginInterface
Registry --> HandlerRegistry
Registry --> AssetPipelines
SessionMgr --> Session
Session --> SessionQueue
SessionQueue --> QueueDB
Session --> Cache
Session --> Repository
QueueDB --> SQLiteQueue
Cache --> Repository
OAMTools --> Repository
Engine Initialization¶
graph LR
subgraph "Engine Initialization"
EngineStart["Engine Start"]
CreateManager["sessions.NewManager()"]
CreateRegistry["registry.New()"]
CreateDispatcher["dispatcher.NewDispatcher()"]
end
subgraph "Registry"
Handlers["handlers map[string]map[int][]*Handler"]
Pipelines["pipelines map[AssetType]*AssetPipeline"]
BuildPipelines["BuildPipelines()"]
end
subgraph "Dispatcher"
DispatchChan["dchan chan *Event"]
CompleteChan["cchan chan *EventDataElement"]
MaintainPipelines["maintainPipelines()"]
end
subgraph "SessionManager"
Sessions["sessions map[uuid.UUID]Session"]
NewSession["NewSession()"]
CancelSession["CancelSession()"]
end
EngineStart --> CreateManager
EngineStart --> CreateRegistry
CreateManager --> CreateDispatcher
CreateRegistry --> CreateDispatcher
CreateRegistry --> Handlers
CreateRegistry --> Pipelines
CreateDispatcher --> DispatchChan
CreateDispatcher --> CompleteChan
CreateDispatcher --> MaintainPipelines
CreateManager --> Sessions
BuildPipelines --> Pipelines
NewSession --> Sessions
Event Dispatch Flow¶
graph TB
subgraph "Event Structure"
EventStruct["Event struct<br/>Name: string<br/>Entity: *dbt.Entity<br/>Meta: interface{}<br/>Dispatcher: Dispatcher<br/>Session: Session"]
end
subgraph "Event Creation and Dispatch"
UserInput["User Input<br/>Domain/IP/CIDR"]
CreateEvent["Create Event"]
DispatchEvent["Dispatcher.DispatchEvent()"]
SafeDispatch["safeDispatch()"]
end
subgraph "Queue Management"
SessionQueue["Session.Queue()"]
QueueAppend["queue.Append(entity)"]
QueueDB["QueueDB.Append()"]
WorkItemsTotal["stats.WorkItemsTotal++"]
end
subgraph "Pipeline Processing"
FillQueues["fillPipelineQueues()"]
GetPipeline["registry.GetPipeline(assetType)"]
AssetPipeline["AssetPipeline<br/>Pipeline + Queue"]
AppendPipeline["appendToPipeline()"]
end
subgraph "Handler Execution"
HandlerTask["handlerTask()"]
PluginCallback["handler.Callback(event)"]
NewEvents["Generate New Events"]
CompleteCallback["completedCallback()"]
WorkItemsCompleted["stats.WorkItemsCompleted++"]
end
UserInput --> CreateEvent
CreateEvent --> EventStruct
EventStruct --> DispatchEvent
DispatchEvent --> SafeDispatch
SafeDispatch --> QueueAppend
QueueAppend --> QueueDB
SafeDispatch --> WorkItemsTotal
SafeDispatch --> AppendPipeline
FillQueues --> SessionQueue
SessionQueue --> GetPipeline
GetPipeline --> AssetPipeline
AssetPipeline --> AppendPipeline
AppendPipeline --> AssetPipeline
AssetPipeline --> HandlerTask
HandlerTask --> PluginCallback
PluginCallback --> NewEvents
PluginCallback --> CompleteCallback
NewEvents --> DispatchEvent
CompleteCallback --> WorkItemsCompleted
Session Internals¶
graph TB
subgraph "Session Structure"
SessionFields["Session struct<br/>id: uuid.UUID<br/>cfg: *config.Config<br/>scope: *scope.Scope<br/>db: repository.Repository<br/>queue: *sessionQueue<br/>cache: *cache.Cache<br/>tmpdir: string<br/>stats: *SessionStats<br/>done: chan struct{}"]
end
subgraph "Session Creation"
NewUUID["uuid.New()"]
SetupDB["setupDB()"]
CreateTmpDir["createTemporaryDir()"]
CreateCache["cache.New(repo, db, ttl)"]
CreateQueue["newSessionQueue(s)"]
end
subgraph "Database Selection"
CheckPrimary["Find Primary DB"]
PostgresPath["Postgres DSN"]
SQLitePath["SQLite DSN"]
Neo4jPath["Neo4j DSN"]
InitStore["assetdb.New(dbtype, dsn)"]
end
subgraph "Temporary Directory Structure"
TmpDir["session-{UUID}/"]
CacheDB["cache.db<br/>SQLite cache repository"]
QueueDBFile["queue.db<br/>SQLite work queue"]
end
SessionFields --> NewUUID
NewUUID --> SetupDB
SetupDB --> CheckPrimary
CheckPrimary --> PostgresPath
CheckPrimary --> SQLitePath
CheckPrimary --> Neo4jPath
PostgresPath --> InitStore
SQLitePath --> InitStore
Neo4jPath --> InitStore
SetupDB --> CreateTmpDir
CreateTmpDir --> TmpDir
TmpDir --> CreateCache
TmpDir --> CreateQueue
CreateCache --> CacheDB
CreateQueue --> QueueDBFile
Storage Tier Details¶
graph TB
subgraph "Storage Tier Overview"
PersistentDB["Persistent Storage<br/>Primary Graph Database"]
SessionCache["Session Cache<br/>cache.Cache"]
WorkQueue["Work Queue<br/>queuedb.QueueDB"]
end
subgraph "Repository Layer"
RepInterface["Repository interface<br/>CreateAsset()<br/>FindEntityById()<br/>Link()<br/>IncomingEdges()<br/>OutgoingEdges()"]
SQLRepo["sqlrepo (Postgres/SQLite)"]
Neo4jRepo["neo4j (Neo4j)"]
end
subgraph "Cache Layer"
CacheStruct["Cache struct<br/>cache: repository.Repository<br/>store: repository.Repository<br/>ttl: time.Duration"]
CacheCreate["CreateAsset()<br/>cache → store if needed"]
TTLManagement["TTL-based expiration"]
end
subgraph "Queue Database"
QueueStruct["QueueDB struct<br/>db: *gorm.DB"]
ElementTable["Element table<br/>ID, etype, entity_id<br/>processed, created_at"]
QueueIndexes["Indexes:<br/>idx_created_at, idx_etype<br/>idx_entity_id (unique)<br/>idx_processed"]
end
PersistentDB --> RepInterface
RepInterface --> SQLRepo
RepInterface --> Neo4jRepo
SessionCache --> CacheStruct
CacheStruct --> CacheCreate
CacheStruct --> TTLManagement
WorkQueue --> QueueStruct
QueueStruct --> ElementTable
ElementTable --> QueueIndexes
GraphQL Client/Server Architecture¶
graph TB
subgraph "Client: internal/enum"
EnumCLI["enum command"]
GraphQLClient["client.Client"]
ClientOps["CreateSession()<br/>CreateAsset()<br/>TerminateSession()<br/>SessionStats()<br/>Subscribe()"]
end
subgraph "Communication Layer"
HTTPClient["http.Client<br/>POST /graphql"]
WSClient["websocket.Conn<br/>ws:// subscription"]
end
subgraph "Server: internal/amass_engine"
EngineCLI["engine command"]
GraphQLServer["GraphQL Server<br/>:4000/graphql"]
Resolvers["schema.resolvers.go<br/>Mutation/Query/Subscription"]
end
subgraph "Engine Core"
EngineDispatcher["Dispatcher"]
EngineSessionMgr["SessionManager"]
EngineRegistry["Registry"]
end
EnumCLI --> GraphQLClient
GraphQLClient --> ClientOps
ClientOps --> HTTPClient
ClientOps --> WSClient
HTTPClient --> GraphQLServer
WSClient --> GraphQLServer
GraphQLServer --> Resolvers
Resolvers --> EngineDispatcher
Resolvers --> EngineSessionMgr
EngineSessionMgr --> EngineDispatcher
EngineDispatcher --> EngineRegistry
EngineCLI --> EngineSessionMgr
EngineCLI --> EngineDispatcher
EngineCLI --> EngineRegistry
Configuration Loading¶
graph TB
subgraph "Configuration Sources"
CLIArgs["CLI Arguments<br/>--flag=value"]
EnvVars["Environment Variables<br/>AMASS_CONFIG<br/>AMASS_DB_*<br/>AMASS_ENGINE_*"]
YAMLFile["config.yaml<br/>User Config Dir"]
SysYAML["config.yaml<br/>/etc/amass/"]
Defaults["System Defaults<br/>config.NewConfig()"]
end
subgraph "Config Structure"
ScopeSection["Scope *Scope<br/>Domains, IPs, ASNs, CIDRs, Ports"]
ResolverSettings["Resolvers []string<br/>TrustedResolvers []string<br/>ResolversQPS int<br/>TrustedQPS int"]
GraphDBSection["GraphDBs []*Database<br/>Primary, System, DSN"]
EngineAPISection["EngineAPI *EngAPI<br/>URL, Host, Port, Path"]
TransformSection["Transformations map[string]*Transformation"]
end
subgraph "Loading Process"
AcquireConfig["AcquireConfig()"]
LoadSettings["LoadSettings(path)"]
UnmarshalYAML["yaml.Unmarshal"]
LoadFunctions["loadDatabaseSettings()<br/>loadResolverSettings()<br/>loadTransformSettings()<br/>loadEngineSettings()"]
end
CLIArgs --> AcquireConfig
EnvVars --> AcquireConfig
YAMLFile --> AcquireConfig
SysYAML --> AcquireConfig
Defaults --> AcquireConfig
AcquireConfig --> LoadSettings
LoadSettings --> UnmarshalYAML
UnmarshalYAML --> ScopeSection
UnmarshalYAML --> ResolverSettings
UnmarshalYAML --> GraphDBSection
UnmarshalYAML --> EngineAPISection
UnmarshalYAML --> TransformSection
LoadSettings --> LoadFunctions
Learn More¶
-
Plugin System
Understand how plugins extend Amass capabilities
-
Data Flow
How assets move through the discovery pipeline