engine

package
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package engine — cloud_attack_paths.go

Phase 16: Internet-to-sensitive-data attack path detection.

DetectCloudAttackPaths bridges the graph traversal engine (Phase 15.1) and the AuditSummary model by converting GraphAttackPath results into models.CloudAttackPath values suitable for JSON output and CLI rendering.

Detection works for both identity paths:

  • Workload → ServiceAccount → IAMRole → Cloud Resource (IRSA)
  • Workload → Node → IAMRole → Cloud Resource (instance profile)

This module only reads the asset graph — it never modifies findings, scores, or any engine state, and it contains no rule-based logic.

Package engine — findings_to_graph.go

Phase 18: Misconfiguration to Attack Path Bridging. EnrichWithFindings converts security rule findings into Misconfiguration graph nodes and attaches them to existing asset graph nodes via AMPLIFIES edges. This allows the graph traversal engine to surface misconfigurations as amplifiers in attack path detection without modifying rule detection logic.

Package engine — kubernetes_attack_paths.go

Phase 15.1: Graph-based attack path detection using the traversal engine. FindGraphAttackPaths discovers attack paths from Internet-exposed entry points through to sensitive cloud resources by traversing the asset graph.

This module is independent of the rule-based correlation in kubernetes_correlation.go; it operates solely on the asset graph topology and cloud resource sensitivity metadata.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DetectCloudAttackPaths added in v0.16.0

func DetectCloudAttackPaths(g *graph.Graph) []models.CloudAttackPath

DetectCloudAttackPaths uses the graph traversal engine to discover all Internet → sensitive cloud resource attack paths in the asset graph.

It delegates path enumeration and scoring to FindGraphAttackPaths (Phase 15.1) and converts the internal GraphAttackPath results into models.CloudAttackPath values for inclusion in AuditSummary.CloudAttackPaths.

Phase 17.1 additions:

  • Severity is derived from score via models.AttackPathSeverityFromScore.
  • HasSensitiveData is set when the target node carries sensitivity=="high".

Returns nil when g is nil or when no qualifying paths exist.

func EnrichWithFindings added in v0.17.0

func EnrichWithFindings(g *graph.Graph, findings []models.Finding)

EnrichWithFindings converts security rule findings into Misconfiguration nodes in the asset graph and links them to the assets they affect via AMPLIFIES edges.

Supported rule mappings:

  • K8S_SERVICE_PUBLIC_LOADBALANCER → Misconfiguration(PublicLoadBalancer) attached to the matching LoadBalancer node (matched by service name from finding ResourceID) via LoadBalancer → Misconfiguration AMPLIFIES edge. Also adds Internet → Misconfiguration EXPOSES edge so the node is reachable from attacker entry points.

  • EKS_NODE_ROLE_OVERPERMISSIVE → Misconfiguration(WildcardIAMRole) attached to every IAMRole node in the graph via IAMRole → Misconfiguration AMPLIFIES edge.

  • K8S_POD_RUN_AS_ROOT / K8S_PRIVILEGED_CONTAINER / K8S_POD_CAP_SYS_ADMIN → Misconfiguration(PrivilegedContainer) attached to the matching Workload node (matched by workload_name metadata or ResourceID) via Workload → Misconfiguration AMPLIFIES edge.

Nodes are added idempotently (first-write-wins in graph.AddNode). Edges are added idempotently (graph.AddEdge is a no-op for duplicate edges). Findings for unrecognised rule IDs are silently ignored. The function is a no-op when g is nil.

func ScorePath

func ScorePath(g *graph.Graph, path traversal.TraversalResult) int

ScorePath computes a risk score (0–110) for a traversal result based on the types of nodes present in the path.

Scoring criteria (additive):

+40  if the path starts at (or contains) an Internet node
+20  if the path passes through a privileged workload (NodeTypeWorkload)
+20  if the path passes through an IAM role (NodeTypeIAMRole)
+20  if the path ends at a sensitive cloud resource (sensitivity == "high")
+10  if the path includes IAMRole → IAMRole privilege escalation (Phase 16.1)

Types

type AWSCostEngine

type AWSCostEngine struct {
	// contains filtered or unexported fields
}

AWSCostEngine is the production implementation of Engine. It coordinates data collection, rule evaluation, and report assembly. It never calls the AWS SDK, LLM, or any external service directly.

func NewAWSCostEngine

func NewAWSCostEngine(
	provider common.AWSClientProvider,
	costCollector awscost.CostCollector,
	registry rules.RuleRegistry,
	policyCfg *policy.PolicyConfig,
) *AWSCostEngine

NewAWSCostEngine constructs a AWSCostEngine wired to the supplied provider, cost collector, and rule registry.

func (*AWSCostEngine) RunAudit

func (e *AWSCostEngine) RunAudit(ctx context.Context, opts AuditOptions) (*models.AuditReport, error)

RunAudit implements Engine. Only AuditTypeCost is supported in the MVP. It loads the requested AWS profile(s), discovers regions if not explicitly provided, collects cost data, evaluates all registered rules, and returns a fully populated AuditReport.

type AWSDataProtectionEngine

type AWSDataProtectionEngine struct {
	// contains filtered or unexported fields
}

AWSDataProtectionEngine implements Engine for AuditTypeDataProtection. It coordinates data collection from two sources:

  • CostCollector: provides per-region EBSVolumes and RDSInstances with their Encrypted / StorageEncrypted fields populated.
  • SecurityCollector: provides account-level S3 bucket data with DefaultEncryptionEnabled populated by GetBucketEncryption.

Rules are evaluated per-region for EBS/RDS and once globally for S3. The engine never calls AWS SDK clients directly.

func NewAWSDataProtectionEngine

func NewAWSDataProtectionEngine(
	provider common.AWSClientProvider,
	cost awscost.CostCollector,
	security awssecurity.SecurityCollector,
	registry rules.RuleRegistry,
	policyCfg *policy.PolicyConfig,
) *AWSDataProtectionEngine

NewAWSDataProtectionEngine constructs a AWSDataProtectionEngine wired to the supplied provider, cost collector, security collector, and rule registry.

func (*AWSDataProtectionEngine) RunAudit

RunAudit implements Engine. Only AuditTypeDataProtection is accepted.

type AWSSecurityEngine

type AWSSecurityEngine struct {
	// contains filtered or unexported fields
}

AWSSecurityEngine implements Engine for AuditTypeSecurity. It coordinates security data collection, rule evaluation, and report assembly. It never calls AWS SDK or LLM clients directly; all calls are delegated to the SecurityCollector and RuleRegistry.

func NewAWSSecurityEngine

func NewAWSSecurityEngine(
	provider common.AWSClientProvider,
	collector awssecurity.SecurityCollector,
	registry rules.RuleRegistry,
	policyCfg *policy.PolicyConfig,
) *AWSSecurityEngine

NewAWSSecurityEngine constructs a AWSSecurityEngine wired to the supplied provider, security collector, and rule registry.

func (*AWSSecurityEngine) RunAudit

RunAudit implements Engine. Only AuditTypeSecurity is accepted.

type AllAWSAuditOptions

type AllAWSAuditOptions struct {
	// Profile is the named AWS profile to use. Empty means the default credential chain.
	Profile string

	// AllProfiles, when true, runs all AWS domain audits across every configured profile.
	AllProfiles bool

	// Regions is an explicit list of AWS regions to audit.
	// When empty each engine discovers and iterates all active regions.
	Regions []string

	// DaysBack is the lookback window in days for cost queries. Defaults to 30 when zero.
	DaysBack int
}

AllAWSAuditOptions configures a cross-domain AWS unified audit run.

type AllAWSDomainsEngine

type AllAWSDomainsEngine struct {
	// contains filtered or unexported fields
}

AllAWSDomainsEngine orchestrates a unified audit across the three AWS domains: cost, security, and dataprotection.

Kubernetes is intentionally excluded. It belongs to its own provider layer (dp kubernetes audit) and must not be invoked from an AWS-scoped audit.

Each domain engine applies its own per-domain policy filtering internally. AllAWSDomainsEngine then concatenates the filtered findings, runs one global mergeFindings pass (cross-domain deduplication by ResourceID+Region), and sorts by severity to produce a single unified AuditReport.

func NewAllAWSDomainsEngine

func NewAllAWSDomainsEngine(
	cost *AWSCostEngine,
	sec *AWSSecurityEngine,
	dp *AWSDataProtectionEngine,
	policyCfg *policy.PolicyConfig,
) *AllAWSDomainsEngine

NewAllAWSDomainsEngine constructs an AllAWSDomainsEngine wired to the three AWS domain engines and shared policy config.

func (*AllAWSDomainsEngine) RunAllAWSAudit

func (e *AllAWSDomainsEngine) RunAllAWSAudit(
	ctx context.Context,
	opts AllAWSAuditOptions,
) (*models.AuditReport, []string, error)

RunAllAWSAudit executes the three AWS domain engines sequentially, checks per-domain policy enforcement, concatenates all policy-filtered findings, runs mergeFindings once for cross-domain deduplication, and sorts globally by severity.

The returned []string lists the domains that triggered policy enforcement (findings at or above the configured fail_on_severity threshold). Callers must inspect this list and exit with code 1 when it is non-empty.

The returned error covers only engine-level failures (provider errors, rule evaluation errors). Policy enforcement is not an error; it is signalled via the returned slice.

type AssumeRoleResolver added in v0.16.0

type AssumeRoleResolver interface {
	ResolveAssumableRoles(ctx context.Context, roleArn string) ([]models.AssumableRole, error)
}

AssumeRoleResolver resolves the set of IAM roles that a given source role can assume via sts:AssumeRole, enabling cross-role privilege escalation detection in the asset graph (Phase 16.1).

The interface is defined here (engine layer) for dependency inversion — the engine never imports the AWS IAM provider package directly. Nil disables IAMRole → IAMRole escalation enrichment on the asset graph.

type AuditOptions

type AuditOptions struct {
	// AuditType selects the audit module (e.g. "cost").
	AuditType AuditType

	// Profile is the named AWS profile to use. Empty means the default profile.
	Profile string

	// AllProfiles, when true, runs the audit across every configured AWS profile.
	AllProfiles bool

	// Regions is an explicit list of AWS regions to audit.
	// When empty the engine discovers and iterates all active regions.
	Regions []string

	// ReportFormat controls how the CLI renders the returned report.
	ReportFormat ReportFormat

	// DaysBack is the lookback window in days for cost and metric queries.
	// Defaults to 30 when zero.
	DaysBack int
}

AuditOptions configures a single audit run. It is the sole input to Engine.RunAudit.

type AuditType

type AuditType string

AuditType identifies the category of audit to run.

const (
	AuditTypeCost           AuditType = "cost"
	AuditTypeSecurity       AuditType = "security"
	AuditTypeDataProtection AuditType = "dataprotection"
	AuditTypeAll            AuditType = "all"
)

type EKSDataCollector

type EKSDataCollector interface {
	CollectEKSData(ctx context.Context, clusterName, region string) (*models.KubernetesEKSData, error)
}

EKSDataCollector collects EKS-specific cluster configuration from the AWS EKS API. The interface is defined here (engine layer) so the engine remains independent of any AWS provider implementation; callers inject the concrete collector. Nil means EKS data collection is disabled and EKS-specific rules are skipped.

type Engine

type Engine interface {
	RunAudit(ctx context.Context, opts AuditOptions) (*models.AuditReport, error)
}

Engine is the central orchestration interface. It coordinates provider collection, rule evaluation, and optional LLM summarization, returning a fully populated AuditReport.

Engine must not call AWS SDK or LLM clients directly; it delegates to the appropriate provider and rule interfaces.

type EngineContext

type EngineContext struct {
	// AssetGraph is the infrastructure relationship graph built from the
	// collected cluster inventory. It encodes Service→Workload routing,
	// Workload→ServiceAccount bindings, and ServiceAccount→IAMRole IRSA links.
	// Nil when no audit has been run yet or when graph construction failed.
	AssetGraph *graph.Graph
}

EngineContext holds ancillary data produced during a single RunAudit call. It is stored on the engine so callers can access it after RunAudit returns without changing the RunAudit return signature.

type GraphAttackPath

type GraphAttackPath struct {
	// Nodes is the ordered sequence of node IDs from Internet to leaf.
	Nodes []string

	// Edges contains human-readable edge descriptors ("fromID→toID").
	Edges []string

	// Score is the computed risk score (0–100).
	Score int

	// Description is a human-readable summary of the path characteristics.
	Description string
}

GraphAttackPath represents a single attack path discovered through graph traversal. Unlike the rule-based AttackPath model, this is derived purely from graph topology and sensitivity metadata.

func FindGraphAttackPaths

func FindGraphAttackPaths(g *graph.Graph) []GraphAttackPath

FindGraphAttackPaths discovers all attack paths from Internet-exposed entry points through to cloud resource leaf nodes in the asset graph.

For each Internet node in the graph, the traversal engine enumerates all distinct paths using the attacker-movement edge set. Paths that do not terminate at a cloud resource node are discarded. Surviving paths are scored via ScorePath and returned sorted by score descending (highest risk first).

type IAMAccessResolver

type IAMAccessResolver interface {
	ResolveRoleResourceAccess(ctx context.Context, roleArn string) ([]models.RoleCloudAccess, error)
}

IAMAccessResolver resolves the AWS cloud resources reachable by an IAM role. The interface is defined here (engine layer) for dependency inversion — the engine never imports the AWS IAM provider package directly. Nil disables cloud reachability enrichment on the asset graph.

type KubernetesAuditOptions

type KubernetesAuditOptions struct {
	// ContextName is the kubeconfig context to connect to.
	// An empty string means use the current context.
	ContextName string

	// ReportFormat controls the output format selected by the CLI layer.
	ReportFormat ReportFormat

	// ExcludeSystem removes findings whose namespace_type metadata is "system"
	// (kube-system, kube-public, kube-node-lease) from the report.
	// Cluster-scoped findings (nodes, EKS-level) are always retained.
	// Default false — all findings are included.
	ExcludeSystem bool

	// MinRiskScore, when > 0, retains only findings whose risk_chain_score is
	// greater than or equal to this value. Findings with no chain score (0) are
	// excluded. Summary.RiskScore is computed before this filter so it always
	// reflects the full pre-filter risk picture.
	// Default 0 — all findings are included regardless of chain score.
	MinRiskScore int

	// ShowRiskChains, when true, groups the post-filter findings by their
	// risk_chain_score and populates Summary.RiskChains with one entry per
	// unique (score, reason) pair, ordered by descending score.
	// Used by the CLI --show-risk-chains flag and included in JSON output.
	// Default false — Summary.RiskChains is nil/empty.
	ShowRiskChains bool
}

KubernetesAuditOptions carries the parameters for a single cluster audit.

type KubernetesEngine

type KubernetesEngine struct {
	// contains filtered or unexported fields
}

KubernetesEngine orchestrates a Kubernetes governance audit. It supports provider-aware rule evaluation: core rules always run; EKS-specific rules run only when the cluster is detected as EKS.

func NewKubernetesEngine

func NewKubernetesEngine(
	provider kube.KubeClientProvider,
	registry rules.RuleRegistry,
	policyCfg *policy.PolicyConfig,
) *KubernetesEngine

NewKubernetesEngine constructs a KubernetesEngine with core rules only. EKS-specific rule evaluation and data collection are disabled. Use NewKubernetesEngineWithEKS to enable provider-aware governance.

func NewKubernetesEngineWithEKS

func NewKubernetesEngineWithEKS(
	provider kube.KubeClientProvider,
	coreRegistry rules.RuleRegistry,
	eksRegistry rules.RuleRegistry,
	eksCollector EKSDataCollector,
	policyCfg *policy.PolicyConfig,
) *KubernetesEngine

NewKubernetesEngineWithEKS constructs a KubernetesEngine with provider-aware governance. When the cluster is detected as EKS:

  • eksCollector fetches control-plane configuration (endpoint, logging, OIDC)
  • eksRegistry rules are evaluated in addition to coreRegistry rules

eksRegistry and eksCollector may be nil (each is independently optional).

func (*KubernetesEngine) AssetGraph

func (e *KubernetesEngine) AssetGraph() *graph.Graph

AssetGraph returns the infrastructure relationship graph built during the most recent RunAudit call. Returns nil when no audit has completed yet or when graph construction failed non-fatally.

func (*KubernetesEngine) RunAudit

RunAudit connects to the cluster, collects inventory, detects the cloud provider, optionally collects EKS control-plane data, evaluates all registered rules, applies policy filtering, and returns a populated AuditReport.

func (*KubernetesEngine) WithAssumeRoleResolver added in v0.16.0

func (e *KubernetesEngine) WithAssumeRoleResolver(resolver AssumeRoleResolver) *KubernetesEngine

WithAssumeRoleResolver injects an optional assume-role resolver into the engine. When set, RunAudit will resolve sts:AssumeRole targets for each IAMRole node in the asset graph and enrich the graph with ASSUME_ROLE edges, enabling detection of cross-role privilege escalation paths (Phase 16.1). Returns the engine to allow fluent chaining.

func (*KubernetesEngine) WithIAMResolver

func (e *KubernetesEngine) WithIAMResolver(resolver IAMAccessResolver) *KubernetesEngine

WithIAMResolver injects an optional IAM access resolver into the engine. When set, RunAudit will call ResolveRoleResourceAccess for each IAMRole node in the asset graph and enrich the graph with CAN_ACCESS edges to cloud resources. Returns the engine to allow fluent chaining.

func (*KubernetesEngine) WithNodeRoleResolver

func (e *KubernetesEngine) WithNodeRoleResolver(resolver NodeIAMRoleResolver) *KubernetesEngine

WithNodeRoleResolver injects an optional node IAM role resolver into the engine. When set, RunAudit will resolve the EC2 instance-profile role for each cluster node and enrich the asset graph with Node → IAMRole (ASSUMES_ROLE) edges, enabling blast-radius traversal via the Workload → Node → IAMRole path. Returns the engine to allow fluent chaining.

type NodeIAMRoleResolver

type NodeIAMRoleResolver interface {
	ResolveNodeIAMRole(ctx context.Context, providerID string) (string, error)
}

NodeIAMRoleResolver resolves the AWS IAM instance-profile role for a Kubernetes worker node given its cloud ProviderID (e.g. "aws:///us-east-1a/i-0123456789abcdef0").

The interface is defined here (engine layer) for dependency inversion — the engine never imports the AWS EC2 provider package directly. Nil disables instance-profile enrichment on the asset graph.

type ReportFormat

type ReportFormat string

ReportFormat controls the CLI output format.

const (
	ReportFormatJSON  ReportFormat = "json"
	ReportFormatTable ReportFormat = "table"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL