You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(profiles): learn DNS baselines and expose DNS CEL matching (NAUT-1588) - #1036
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.
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):
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.
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.
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: 4 · 1
Failed checks: 1 warning
Check name
Status
Explanation
Resolution
Docstring Coverage
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 checks: 4 passed
Check name
Status
Explanation
Description Check
Check skipped - CodeRabbit’s high-level summary is enabled.
Title check
The title clearly and concisely describes the main changes: learning DNS baselines and exposing DNS CEL matching.
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
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.
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>
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.
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>
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>
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.
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>
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.
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_resolvedandcp.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.mddefines 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 binarypasses; 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