Skip to content

feat(profiles): learn DNS baselines and expose DNS CEL matching (NAUT-1588) - #1036

Open
matthyx wants to merge 6 commits into
mainfrom
fix/naut-1588-dns-baseline
Open

matthyx wants to merge 6 commits into
mainfrom
fix/naut-1588-dns-baseline

Conversation

@matthyx

@matthyx matthyx commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

DNS anomaly rules currently infer DNS history from connection destinations, missing successful lookups without connections and in-cluster/reverse names. Learn an independent DNS baseline from successful answered responses during the existing container learning window, without changing network destinations.

Store canonical names, executable-path sets and capped IP evidence; preserve DNS through report flushes, splitting, dropped-chunk stitches, projection and authored container sections. Expose cp.was_dns_resolved and cp.was_dns_resolved_by_process. Require completed/full, DNS-aware, nontruncated profiles and preserve unavailable errors through CEL negation. Completed containers cannot learn new names from lookups or alerts. Names are capped at 4096; uncertain/overflowed baselines require explicit relearning.

Depends on kubescape/storage#431, pinned to its published commit. Paired R0005 migration: kubescape/rulelibrary#51. Private host/generation adapter: https://github.com/armosec/private-node-agent/pull/711; private rules: https://github.com/armosec/rulelibrary/pull/172. docs/dns-baseline.md defines learning, upgrade/mixed-version reset, stable-identity behavior and rollout order.

Validation: all targeted profile manager, queue, CEL, projection and watcher package suites pass against the published storage pin; make binary passes; public-agent vet and changed-code lint pass. Tests cover DNS-only/cluster/reverse names, process isolation, readiness, caps, deferred-peer flushes, dropped chunks and unchanged connection baselines. Independent code review APPROVE and architecture CLEAR. NAUT-1588.

Coordinated PRs (deploy storage, then agents; release draft rules after relearning):

Summary by CodeRabbit

  • New Features
    • Container profiles now learn DNS names from successful responses, even when no network connection is observed. Names are normalized, and recorded executable paths can be used to check whether a specific process resolved a domain.
    • DNS profile data includes limits and a truncation status. DNS checks report an unavailable-profile error when the baseline is incomplete, truncated, outdated, or unavailable.
    • Added guidance on DNS baseline behavior and rollout requirements.

…g (NAUT-1588)

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2772fb84-6f40-4c53-a531-6de6c5f68c0f
📥 Commits

Reviewing files that changed from the base of the PR and between de8f8ed and fb48c45.

⛔ Files ignored due to path filters: 1
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing: 22
  • .github/workflows/component-tests.yaml
  • docs/dns-baseline.md
  • go.mod
  • pkg/containerprofilemanager/v1/containerprofile_manager.go
  • pkg/containerprofilemanager/v1/dns.go
  • pkg/containerprofilemanager/v1/dns_test.go
  • pkg/containerprofilemanager/v1/lifecycle.go
  • pkg/containerprofilemanager/v1/monitoring.go
  • pkg/containerprofilemanager/v1/monitoring_timestamp_test.go
  • pkg/containerwatcher/v2/event_handler_factory.go
  • pkg/containerwatcher/v2/tracers/dns.go
  • pkg/containerwatcher/v2/tracers/dns_capture_learning_test.go
  • pkg/containerwatcher/v2/tracers/dns_retry_test.go
  • pkg/containerwatcher/v2/tracers/tracer_factory.go
  • pkg/objectcache/containerprofilecache/containerprofilecache.go
  • pkg/objectcache/containerprofilecache/dns_snapshot_test.go
  • pkg/objectcache/containerprofilecache_interface.go
  • pkg/objectcache/v1/mock.go
  • pkg/rulemanager/cel/libraries/containerprofile/dns.go
  • pkg/rulemanager/cel/libraries/containerprofile/dns_test.go
  • tests/scripts/storage-tag.sh
  • tests/scripts/test_storage_tag.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The agent now learns DNS lookup baselines from successful DNS responses and includes version and truncation metadata in container profiles. The object cache projects this data, and two CEL helpers match domains with optional executable-path checks while reporting unavailable-baseline errors. Component tests now prepare storage images for module pseudo-versions.

Changes: DNS baseline

Layer / File(s) Summary
Collect DNS events and emit profile baselines
go.mod, pkg/containerprofilemanager/..., pkg/containerwatcher/v2/..., docs/dns-baseline.md
The watcher reports DNS events and collector availability to the profile manager. The manager records normalized names, executable paths, and valid addresses within configured limits. Profile reports include DNS lookups, baseline version, and truncation status.
Preserve baseline completeness across profile chunks
pkg/containerprofilemanager/v1/queue/containerprofile_split.go, pkg/containerprofilemanager/v1/queue/containerprofile_split_test.go
Splitting partitions DNS lookups across profile chunks. Stitching preserves the baseline version and marks the baseline truncated when a chunk with DNS lookups is dropped.
Project DNS baseline data
pkg/objectcache/projection_types.go, pkg/objectcache/containerprofilecache/*, pkg/objectcache/v1/mock.go
Projected profiles include DNS baseline metadata and normalized lookup names mapped to executable-path sets. Authored sections and cache mocks also copy the DNS fields. The cache can return a profile and its state from one snapshot read.
Add CEL DNS matching and readiness errors
pkg/rulemanager/cel/libraries/containerprofile/*
The DNS helpers match normalized domains, optionally against an executable path. They return errors for unavailable or incomplete DNS baselines and bypass the existing helper cache and unavailable-profile-to-false conversion.
Prepare storage images for component tests
.github/workflows/component-tests.yaml, tests/scripts/storage-tag.sh, tests/scripts/test_storage_tag.py
The workflow builds and loads a local storage image for pseudo-versions and passes the selected image tag and pull policy to Helm. The tag script rejects pseudo-versions and tests cover release-tag selection.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant DNSTracer
  participant EventHandlerFactory
  participant ContainerProfileManager
  participant ContainerProfile
  participant ObjectCache
  participant DNSCELHelper
  DNSTracer->>EventHandlerFactory: Deliver DNS event
  EventHandlerFactory->>ContainerProfileManager: ReportDNSEvent
  ContainerProfileManager->>ContainerProfile: Emit DNS baseline fields
  ContainerProfile->>ObjectCache: Provide profile DNS data
  ObjectCache->>DNSCELHelper: Return projected DNS baseline and state
  DNSCELHelper->>DNSCELHelper: Match domain and optional executable path
Loading
Merge Risk: ⚪ Minimal · up to fb48c

No merge-blocking issue was identified in the reviewed changes; the PR is ready for normal merge checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 35.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 40 functions across 30 files. (3 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main changes: learning DNS baselines and exposing DNS CEL matching.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 35.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 40 functions across 30 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@matthyx
matthyx requested a balanced review from Copilot October 15, 2026 15:27
@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.210 0.211 +0.6%
Peak CPU (cores) 0.219 0.218 -0.4%
Peak CPU p95 (cores) 0.217 0.216 -0.6%
Avg Memory (MiB) 382.075 323.856 -15.2%
Peak Memory (MiB) 385.402 334.301 -13.3%
Dedup Effectiveness

No data available.

@matthyx
matthyx requested a balanced review from Copilot and removed request for Copilot October 15, 2026 15:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Disabled DNS collection and stale cached results can make unavailable baselines produce false anomaly alerts.

2 open findings

🧠 Review effort: Balanced

Comment thread pkg/containerprofilemanager/v1/monitoring.go
Comment thread pkg/rulemanager/cel/libraries/containerprofile/containerprofile.go Outdated
Mark DNS-disabled collection windows truncated and bypass result caching for DNS helpers so current profile readiness is always checked. Add regressions for disabled tracing and refreshed unavailable profiles.

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Cache-refresh races and discarded root-domain observations can produce false DNS anomaly alerts.

1 open finding
2 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Preserve DNS root name '.' during lookup learning and matching

pkg/​containerprofilemanager/​v1/​dns.go:21

A successful NS/SOA lookup of the DNS root has the valid name .. Trimming its trailing dot makes it empty, so this guard discards the observation. After learning completes, cp.was_dns_resolved(containerId, '.') therefore returns false even for a previously observed lookup, and negation can produce a false anomaly. Distinguish a missing name from the root name. Preserve . in storage consolidation too: DeflateDNSLookups in the pinned storage commit applies the same empty-name filter. Add a root-name learning and matching regression test.

🧠 Review effort: Balanced

Comment thread pkg/rulemanager/cel/libraries/containerprofile/dns.go Outdated
Read DNS readiness and projection from one cache entry. Preserve valid root-domain observations through learning, storage and CEL matching; pin the storage correction. Cover refresh races and root lookups with regressions.

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.000 0.000 N/A
Peak CPU (cores) 0.000 0.000 N/A
Peak CPU p95 (cores) 0.000 0.000 N/A
Avg Memory (MiB) 0.000 0.000 N/A
Peak Memory (MiB) 0.000 0.000 N/A
Dedup Effectiveness

No data available.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Collector-failure handling remains unresolved, and coordinated storage, agent, and rule rollout requires human validation.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Comment thread pkg/containerprofilemanager/v1/monitoring.go Outdated
Track actual DNS collector startup, stop and retry availability. Keep every overlapping learning window truncated across recovery using a collector generation, and require a fresh window to regain readiness. Cover startup failure and recovery in profiler and tracer tests.

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@matthyx
matthyx requested a balanced review from Copilot October 15, 2026 16:36
@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.000 0.000 N/A
Peak CPU (cores) 0.000 0.000 N/A
Peak CPU p95 (cores) 0.000 0.000 N/A
Avg Memory (MiB) 0.000 0.000 N/A
Peak Memory (MiB) 0.000 0.000 N/A
Dedup Effectiveness

No data available.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Learning finalization needs correction, and collector lifecycle plus coordinated storage/rule rollout require human integration validation.

0 open findings

1 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Finalize profiling only after queued pre-completion responses are flushed

pkg/​containerprofilemanager/​v1/​dns.go:30

This guard drops responses captured during learning if they reach profiling after completion. The watcher batches events on a 50 ms tick, but monitoring.go:145–147 sets Completed before flushAndSettle; successful termination also sets Completed before the final flush. DNS handlers run sequentially, and the DNS manager currently runs first (event_handler_factory.go:462), so its synchronous net.LookupIP for uncached TXT/PTR responses without addresses can extend this delay. These observations can be omitted from an otherwise full, nontruncated baseline, causing false anomalies later.

Coordinate finalization with delivery of pre-cutoff responses before publishing the completed profile, while still rejecting genuinely post-completion lookups. Moving profiling before the DNS manager avoids the lookup delay but does not solve queued-event loss. Add regressions for a response queued before completion and one delayed by DNS resolution.

🧠 Review effort: Balanced

Deliver DNS observations to learning at capture before asynchronous queueing and DNS resolution can delay them past completion. Keep post-completion rejection, and cover queued/addressless responses with a regression.

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@matthyx

matthyx commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the previously missed finalization finding from Copilot review 5536703618 in 2acbe64. DNS observations reach profiling synchronously at the tracer capture callback, before the asynchronous queue and downstream DNS resolution. Queued/addressless responses are learned before completion; genuinely post-completion responses remain rejected. The regression fails before this change and passes afterward, including under race. Watcher and unprivileged tracer suites, vet and binary build pass. Four privileged eBPF field tests remain blocked by local map-creation permissions.

This run reached the five-request review limit. No additional Copilot pass was requested on this final commit.

@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.000 0.000 N/A
Peak CPU (cores) 0.000 0.000 N/A
Peak CPU p95 (cores) 0.000 0.000 N/A
Avg Memory (MiB) 0.000 0.000 N/A
Peak Memory (MiB) 0.000 0.000 N/A
Dedup Effectiveness

No data available.

@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.149 0.143 -4.3%
Peak CPU (cores) 0.157 0.150 -4.2%
Peak CPU p95 (cores) 0.154 0.149 -3.5%
Avg Memory (MiB) 367.117 314.541 -14.3%
Peak Memory (MiB) 369.695 321.047 -13.2%
Dedup Effectiveness

No data available.

Do not treat Go pseudo-versions as published image tags. Build the checksum-verified pinned storage source once, share its image artifact across the matrix and load it into Kind with pullPolicy Never. Preserve release-tag selection and guard it with regressions.

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.191 0.219 +14.8%
Peak CPU (cores) 0.200 0.228 +14.1%
Peak CPU p95 (cores) 0.198 0.227 +14.6%
Avg Memory (MiB) 374.525 314.070 -16.1%
Peak Memory (MiB) 377.988 321.789 -14.9%
Dedup Effectiveness

No data available.

@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.227 0.216 -4.8%
Peak CPU (cores) 0.234 0.223 -4.7%
Peak CPU p95 (cores) 0.233 0.219 -6.0%
Avg Memory (MiB) 380.522 314.635 -17.3%
Peak Memory (MiB) 383.219 322.949 -15.7%
Dedup Effectiveness

No data available.

@matthyx matthyx moved this to WIP in KS PRs tracking Oct 16, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: WIP

Development

Successfully merging this pull request may close these issues.

2 participants