Skip to content

AuthZService: improve authz caching#3

Closed
ShashankFC wants to merge 1 commit into
cache-optimization-baselinefrom
authz-service-improve-caching-pr
Closed

AuthZService: improve authz caching#3
ShashankFC wants to merge 1 commit into
cache-optimization-baselinefrom
authz-service-improve-caching-pr

Conversation

@ShashankFC

@ShashankFC ShashankFC commented Dec 31, 2025

Copy link
Copy Markdown
Collaborator

Test 2nn

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced permission caching mechanism to accelerate authorization checks.
    • Implemented fast-path evaluation for previously cached permissions.
    • Added denial caching to eliminate redundant permission evaluations.
  • Performance

    • Optimized identity permission lookups through improved caching layer.
    • Reduced database queries for authorization checks.
    • Enhanced authorization metrics tracking and tracing.

✏️ Tip: You can customize this high-level summary in your review settings.

nn---n*Replicated from [ai-code-review-evaluation/grafana-coderabbit#2](https://github.com/ai-code-review-evaluation/grafana-coderabbit/pull/2)*

* remove the use of client side cache for in-proc authz client

Co-authored-by: Gabriel MABILLE <gabriel.mabille@grafana.com>

* add a permission denial cache, fetch perms if not in either of the caches

Co-authored-by: Gabriel MABILLE <gabriel.mabille@grafana.com>

* Clean up tests

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

* Cache tests

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

* Add test to list + cache

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

* Add outdated cache test

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

* Re-organize metrics

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>

---------

Co-authored-by: Gabriel MABILLE <gabriel.mabille@grafana.com>
@ShashankFC

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jan 12, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jan 12, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The pull request implements permission-denial caching for RBAC authorization checks. It introduces a NoopCache type for the authz client, adds a permission denial cache field to the Service, and implements fast-path logic that checks cached denials and cached identity permissions before querying the database. Test coverage is expanded to validate cache hit, miss, and denial scenarios.

Changes

Cohort / File(s) Summary
Cache Implementation
pkg/services/authz/rbac.go, pkg/services/authz/rbac/cache.go
Replaces remote RBAC client creation with authzlib.NewClient using NoopCache. Adds exported NoopCache type with Get (returns NotFound), Set, and Delete methods. Adds internal userPermDenialCacheKey helper to construct cache keys for permission denials.
Service Integration
pkg/services/authz/rbac/service.go
Introduces permDenialCache field to Service struct. Adds getCachedIdentityPermissions method for fetching cached permissions with fallback to database. Implements fast-path denial check in Check method and cached-first lookup in List method. Removes direct in-method cache lookups, centralizing caching logic.
Test Coverage
pkg/services/authz/rbac/service_test.go
Removes outdated cache lookup test. Adds TestService_CacheCheck and TestService_CacheList to validate cache hits, misses, outdated cache, and denial scenarios. Updates setupService factory to initialize permDenialCache.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Service
    participant PermDenialCache
    participant CachedPermCache
    participant Database
    
    Client->>Service: Check(ctx, identity, action, resource)
    Service->>PermDenialCache: Get(key)
    alt Denial Cached
        PermDenialCache-->>Service: true (NotFound error)
        Service-->>Client: false (denied, metrics updated)
    else Not Cached
        Service->>CachedPermCache: getCachedIdentityPermissions(...)
        alt Cache Hit
            CachedPermCache-->>Service: map[string]bool
            Service->>Service: checkPermission(map)
            Service-->>Client: bool result
        else Cache Miss
            CachedPermCache->>Database: Query permissions
            Database-->>CachedPermCache: Permissions
            CachedPermCache-->>Service: Permissions
            Service->>Service: Evaluate permissions
            alt Denied
                Service->>PermDenialCache: Set(key, true)
            end
            Service-->>Client: bool result
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Through the cache we bound with permission in sight,
Denials remembered, no database flight,
Fast-path leaps forward when answers are near,
Fallback to queries when cache isn't clear,
Authorization accelerates—hop, hop, hooray! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: improving authz caching by introducing a denial cache, fast-path workflows, and centralized caching strategies.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 0

🧹 Nitpick comments (3)
pkg/services/authz/rbac.go (1)

239-251: Consider adding a brief doc comment for the exported type.

The NoopCache implementation is correct. Since it's an exported type, a short doc comment explaining its purpose (disabling client-side caching for in-process scenarios) would improve discoverability.

📝 Suggested documentation
+// NoopCache is a cache implementation that never stores data.
+// It is used for in-process clients where server-side caching is preferred.
 type NoopCache struct{}
pkg/services/authz/rbac/service_test.go (2)

973-995: Test correctly validates denial cache precedence.

This test properly verifies that the denial cache takes precedence over other cached permissions. Note that line 982 sets the permission value to false, which wouldn't grant access anyway due to how scopeMap[key] is evaluated in checkPermission. If the intent is to prove that permCache is entirely bypassed when denial cache hits, consider using true:

📝 Minor clarity improvement
 		// Allow access to the dashboard to prove this is not checked
-		s.permCache.Set(ctx, userPermCacheKey("org-12", "test-uid", "dashboards:read"), map[string]bool{"dashboards:uid:dash1": false})
+		s.permCache.Set(ctx, userPermCacheKey("org-12", "test-uid", "dashboards:read"), map[string]bool{"dashboards:uid:dash1": true})

1291-1323: Consider adding cache miss test for List operation.

The test covers the cache hit scenario well. For parity with TestService_CacheCheck, consider adding a test case that verifies List correctly falls back to the database when permissions are not cached.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e650fa7 and d9dc93c.

📒 Files selected for processing (4)
  • pkg/services/authz/rbac.go
  • pkg/services/authz/rbac/cache.go
  • pkg/services/authz/rbac/service.go
  • pkg/services/authz/rbac/service_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/services/authz/rbac/service_test.go (2)
public/app/api/clients/advisor/endpoints.gen.ts (1)
  • Check (382-390)
packages/grafana-data/src/index.ts (1)
  • Scope (573-573)
pkg/services/authz/rbac.go (1)
pkg/services/authz/zanzana/client.go (1)
  • NewClient (23-25)
🔇 Additional comments (8)
pkg/services/authz/rbac.go (1)

101-105: LGTM - Appropriate use of NoopCache for in-process client.

Using NoopCache for the in-process client makes sense since the server-side Service already maintains its own caching layer (via permCache, permDenialCache, etc.). This avoids redundant caching at the client level when both client and server run in the same process.

pkg/services/authz/rbac/cache.go (1)

30-32: LGTM - Cache key follows established patterns.

The key structure mirrors existing cache key functions. The inclusion of name and parent in the denial cache key correctly scopes denials to specific resource instances.

pkg/services/authz/rbac/service_test.go (1)

1336-1336: LGTM - Test setup correctly initializes the new denial cache.

The permDenialCache is properly initialized in setupService, enabling the new cache tests to function correctly.

pkg/services/authz/rbac/service.go (5)

56-61: LGTM - Struct fields properly organized with new denial cache.

The addition of permDenialCache follows the established pattern for cache fields in the service.


116-137: Verify the caching strategy handles stale caches correctly.

The fast-path logic correctly prioritizes the denial cache. The fallthrough to DB when cached permissions don't grant access (lines 131-136) handles the "outdated cache" scenario mentioned in tests.

One consideration: if a user genuinely lacks permission for a resource, every first request will traverse: denial cache miss → permission cache hit (but no match) → DB query → denial cached. The permissionCacheUsage metric on line 137 will record a "miss" even though the permission cache was consulted. This is technically accurate (no cache-based decision was made), but worth noting in observability documentation.


153-155: LGTM - Denial caching after authoritative DB check.

Caching denials only after the full DB permission check ensures we don't cache false negatives from stale/incomplete permission caches. This asymmetric approach (explicit denial cache + permission cache for grants) is sound.


342-368: LGTM - Cached permission lookup correctly handles all identity types.

The implementation properly:

  • Returns cache.ErrNotFound for render service (since those permissions are hardcoded, not cached)
  • Leverages GetUserIdentifiers which has its own caching layer for user/service-account lookups
  • Uses consistent cache keys matching what getUserPermissions/getAnonymousPermissions populate

180-192: LGTM - List uses straightforward cache-or-DB pattern.

Unlike Check which needs the denial cache for specific resource+folder combinations, List correctly uses a simple cache-hit-or-fetch pattern since it returns the complete permission set for an action.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 2 weeks if no further activity occurs. Please feel free to give a status update or ping for review. Thank you for your contributions!

@github-actions github-actions Bot added the stale label Feb 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it has not had any further activity in the last 2 weeks. Thank you for your contributions!

@github-actions github-actions Bot closed this Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants