Skip to content

feat: rbac config access#1894

Merged
moshloop merged 10 commits intomainfrom
k8s-config-access
Feb 12, 2026
Merged

feat: rbac config access#1894
moshloop merged 10 commits intomainfrom
k8s-config-access

Conversation

@yashmehrotra
Copy link
Member

@yashmehrotra yashmehrotra commented Feb 9, 2026

Fixes: #1844

Summary by CodeRabbit

  • New Features

    • Added Kubernetes RBAC extraction and tracking for Roles, RoleBindings, ClusterRoles, and ClusterRoleBindings
    • Config access relationships now captured for RBAC-managed resources and associated users, groups, and service accounts
    • Added a file-based scraper configuration and test fixture to drive RBAC scenarios
  • Tests

    • Added comprehensive unit tests and end-to-end suites validating RBAC extraction, entity persistence, and access resolution
    • Minor test formatting adjustments
  • Chores

    • Improved test environment setup and error handling in build scripts

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a Kubernetes RBAC extractor and integrates it into the Kubernetes scraper; includes fixtures, unit and end-to-end tests, and Makefile updates for envtest setup.

Changes

Cohort / File(s) Summary
Test Fixtures
fixtures/data/k8s_rbac_access_test.json, fixtures/file-k8s-rbac-access.yaml
New JSON fixture defining a Pod and RBAC access mappings and a ScrapeConfig YAML referencing that fixture.
RBAC Extractor Implementation
scrapers/kubernetes/rbac.go
New RBAC extractor implementing CRD-aware resource→Kind mapping, in-memory indexing, Role/ClusterRole parsing, RoleBinding/ClusterRoleBinding processing, generation of ExternalRole/ExternalUser/ExternalGroup and ConfigAccess entries, caching and helpers.
Kubernetes Scraper Integration
scrapers/kubernetes/kubernetes.go
Integrates extractor into ExtractResults: conditionally initializes extractor, indexes objects, processes Roles immediately, defers and later processes bindings, and appends aggregated RBAC results to scrape output.
RBAC Unit Tests
scrapers/kubernetes/rbac_test.go
Comprehensive unit tests for role and binding processing (ServiceAccount/User/Group), namespace vs cluster scope, deduplication, and CRD resource resolution.
End-to-end Tests
scrapers/run_test.go
Adds two large E2E test suites that persist a ScrapeConfig, run the scraper, and verify persistence/resolution of ExternalRole/ExternalUser/ExternalGroup and ConfigAccess entries (appears duplicated).
Small Test Edit
scrapers/extraction_unit_test.go
Whitespace reformat in TestExtractConfigAccess (no behavioral change).
Build/Test Makefile
Makefile
Adds validate-envtest-assets helper, centralizes envtest asset validation/setup, updates ENVTEST_K8S_VERSION and branch selection, and invokes validation in test targets.

Sequence Diagram(s)

sequenceDiagram
    participant Scraper as Kubernetes Scraper
    participant RBAC as RBAC Extractor
    participant RoleIdx as Role Processor
    participant BindingCol as Binding Collector
    participant Results as Results Aggregator

    Scraper->>RBAC: Initialize extractor (cluster, scraperID)
    Scraper->>RBAC: Index all objects
    RBAC->>RoleIdx: Process Role / ClusterRole objects
    RoleIdx-->>RBAC: Store ExternalRole entries
    Scraper->>BindingCol: Collect RoleBinding / ClusterRoleBinding (deferred)
    BindingCol->>RBAC: Process bindings -> resolve subjects, create ExternalUser/ExternalGroup, create ConfigAccess
    RBAC->>Results: Aggregate ExternalRoles, ExternalUsers, ExternalGroups, ConfigAccess
    Results-->>Scraper: Append RBAC results to scrape output
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 'feat: rbac config access' accurately captures the main change: implementing RBAC config access functionality for Kubernetes.
Linked Issues check ✅ Passed The PR addresses issue #1844 by implementing RBAC access tracking, which aligns with the issue's objective of Kubernetes access implementation.
Out of Scope Changes check ✅ Passed All changes relate directly to implementing RBAC config access: test fixtures, extractors, test coverage, and Makefile updates for testing infrastructure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch k8s-config-access

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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 and usage tips.

}

// builtinResourceKinds maps plural resource names to their Kind for core Kubernetes resources.
var builtinResourceKinds = map[string]string{
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be more dynamic ?

Copy link
Member Author

Choose a reason for hiding this comment

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

these are the builtin ones, we scrape crds for getting other resources

@yashmehrotra yashmehrotra marked this pull request as ready for review February 10, 2026 07:00
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@scrapers/kubernetes/rbac_test.go`:
- Around line 96-103: The test for ConfigAccess (using extractor.getAccess() in
rbac_test.go) is missing assertions for ExternalRoleAliases; update the unit
test to assert that each returned ConfigAccess has ExternalRoleAliases set to
the expected slice (matching the fixture k8s_rbac_access_test.json), and if
failures occur, fix the extractor code in rbac.go (the logic that builds
ConfigAccess entries) so it copies the external_role_aliases field into the
ConfigAccess.ExternalRoleAliases before returning; locate code that constructs
ConfigAccess objects and ensure ExternalRoleAliases is populated from the parsed
fixture data, then add assertions in the loop in rbac_test.go to validate the
expected role alias values.

In `@scrapers/kubernetes/rbac.go`:
- Around line 386-407: The ExternalConfigAccess entries created in the loop are
missing ExternalRoleAliases and the embedded ConfigAccess.ID, which breaks
dedup/upsert; compute the role alias once for the binding (the same value used
elsewhere for roles, e.g., the pattern produced for Kubernetes/<cluster>/Role...
or using the same helper used for role aliases), call generateRBACID(subject,
target, roleAlias) to produce a stable ID, and set access.ID to that generated
ID and access.ExternalRoleAliases = []string{roleAlias} when building the
v1.ExternalConfigAccess; locate this change around the block that constructs
v1.ExternalConfigAccess (use symbols KubernetesAlias, GetConfigTypeForKind,
generateRBACID, ExternalConfigAccess) and ensure the roleAlias is computed
before iterating subjects so every access entry gets the same role alias and
deterministic ID.
🧹 Nitpick comments (5)
scrapers/kubernetes/rbac_test.go (1)

362-398: makeRoleBinding and makeClusterRoleBinding share duplicated subject-building logic.

The subject map construction (lines 363–378 and 401–416) is identical. Consider extracting a shared helper.

scrapers/kubernetes/kubernetes.go (1)

568-572: An empty ScrapeResult is always appended when RBAC produces no entities.

When rbac is nil, results() returns v1.ScrapeResult{}. When rbac is non-nil but no RBAC objects exist, it returns a ScrapeResult with empty slices and zero-value fields (no Name, Type, etc.). Either way, an effectively empty result is appended. Consider guarding against this.

Proposed fix
 	// Process role bindings after all roles have been processed
 	for _, binding := range roleBindings {
 		rbac.processRoleBinding(binding)
 	}
-	results = append(results, rbac.results(ctx.config.BaseScraper))
+	if rbacResult := rbac.results(ctx.config.BaseScraper); rbacResult.HasRBACData() {
+		results = append(results, rbacResult)
+	}

Alternatively, perform a simpler check:

-	results = append(results, rbac.results(ctx.config.BaseScraper))
+	rbacResult := rbac.results(ctx.config.BaseScraper)
+	if len(rbacResult.ExternalRoles) > 0 || len(rbacResult.ExternalUsers) > 0 || len(rbacResult.ExternalGroups) > 0 || len(rbacResult.ConfigAccess) > 0 {
+		results = append(results, rbacResult)
+	}
scrapers/kubernetes/rbac.go (3)

414-436: Wildcard resource "*" is silently skipped — consider documenting this trade-off.

When an RBAC rule grants access to resources: ["*"], findTargetResources skips it entirely (line 416-418). This is a reasonable choice to avoid an explosion of access entries for overly permissive roles like cluster-admin, but the behavior should be documented so future maintainers understand the intentional gap.

Add a comment explaining the rationale
 		for _, resourceType := range rule.Resources {
 			if resourceType == "*" {
+				// Wildcard resource access is intentionally skipped to avoid
+				// generating an access entry for every object in the cluster.
+				// Roles like cluster-admin would otherwise produce O(N) entries.
 				continue
 			}

80-92: Global mutable cache — consider documenting thread-safety guarantees.

crdResourceKindCache is a package-level mutable with a mutex. The current usage in fetchCRDResourceKinds is correct (lock/unlock protects reads and writes), and callers only read the returned map, so there's no data race. However, the returned map[string]string is a reference to the cached data — if any future caller were to mutate it, the cache would be corrupted. newRBACExtractor correctly copies entries into a new map, but this invariant is fragile.


96-148: fetchCRDResourceKinds holds the mutex during the entire CRD API call.

The lock is acquired at line 97 and held through the network call to list CRDs (line 128) and cache update (line 142). If the API call is slow or times out, all other goroutines calling this function for any cluster will block. Consider a lock-per-cluster approach or releasing the lock before the API call and re-acquiring it for the cache update (double-check pattern).

Comment on lines 96 to 103
access := extractor.getAccess()
require.Len(t, access, 2, "expected 2 config access entries (one per pod in namespace)")

// Check that access entries point to pods, not the role
for _, a := range access {
assert.Equal(t, ConfigTypePrefix+"Pod", a.ConfigExternalID.ConfigType)
assert.Equal(t, []string{expectedUserAlias}, a.ExternalUserAliases)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Tests don't verify ExternalRoleAliases on ConfigAccess entries.

None of the unit tests assert that ExternalRoleAliases is set on the generated ConfigAccess entries. Given that the test fixture (k8s_rbac_access_test.json) includes external_role_aliases on every config_access entry, this seems like intended behavior that isn't being tested or produced by the extractor. See the related comment on rbac.go for the root cause.

🤖 Prompt for AI Agents
In `@scrapers/kubernetes/rbac_test.go` around lines 96 - 103, The test for
ConfigAccess (using extractor.getAccess() in rbac_test.go) is missing assertions
for ExternalRoleAliases; update the unit test to assert that each returned
ConfigAccess has ExternalRoleAliases set to the expected slice (matching the
fixture k8s_rbac_access_test.json), and if failures occur, fix the extractor
code in rbac.go (the logic that builds ConfigAccess entries) so it copies the
external_role_aliases field into the ConfigAccess.ExternalRoleAliases before
returning; locate code that constructs ConfigAccess objects and ensure
ExternalRoleAliases is populated from the parsed fixture data, then add
assertions in the loop in rbac_test.go to validate the expected role alias
values.

@moshloop moshloop enabled auto-merge (squash) February 12, 2026 09:47
@moshloop moshloop merged commit dcff3ba into main Feb 12, 2026
13 of 15 checks passed
@moshloop moshloop deleted the k8s-config-access branch February 12, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement kubernetes access / logs

2 participants

Comments