Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4cbbd13

Browse files
authored
feat: Turn on rbac check caching (#6202)
* chore: Turn on rbac check caching.Should not affect much unless authz_querier experiment isenabled
1 parentfac7c02 commit4cbbd13

File tree

9 files changed

+61
-9
lines changed

9 files changed

+61
-9
lines changed

‎coderd/coderd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func New(options *Options) *API {
187187
options.PrometheusRegistry=prometheus.NewRegistry()
188188
}
189189
ifoptions.Authorizer==nil {
190-
options.Authorizer=rbac.NewAuthorizer(options.PrometheusRegistry)
190+
options.Authorizer=rbac.NewCachingAuthorizer(options.PrometheusRegistry)
191191
}
192192
ifoptions.TailnetCoordinator==nil {
193193
options.TailnetCoordinator=tailnet.NewCoordinator()
@@ -289,6 +289,7 @@ func New(options *Options) *API {
289289
tracing.StatusWriterMiddleware,
290290
tracing.Middleware(api.TracerProvider),
291291
httpmw.AttachRequestID,
292+
httpmw.AttachAuthzCache,
292293
httpmw.ExtractRealIP(api.RealIPConfig),
293294
httpmw.Logger(api.Logger),
294295
httpmw.Prometheus(options.PrometheusRegistry),

‎coderd/coderdtest/coderdtest.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can
184184
ifstrings.Contains(os.Getenv("CODER_EXPERIMENTS_TEST"),string(codersdk.ExperimentAuthzQuerier)) {
185185
ifoptions.Authorizer==nil {
186186
options.Authorizer=&RecordingAuthorizer{
187-
Wrapped:rbac.NewAuthorizer(prometheus.NewRegistry()),
187+
Wrapped:rbac.NewCachingAuthorizer(prometheus.NewRegistry()),
188188
}
189189
}
190190
options.Database=dbauthz.New(options.Database,options.Authorizer,slogtest.Make(t,nil).Leveled(slog.LevelDebug))

‎coderd/httpmw/authz.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package httpmw
33
import (
44
"net/http"
55

6-
"github.com/coder/coder/coderd/database/dbauthz"
7-
86
"github.com/go-chi/chi/v5"
7+
8+
"github.com/coder/coder/coderd/database/dbauthz"
9+
"github.com/coder/coder/coderd/rbac"
910
)
1011

1112
// AsAuthzSystem is a chained handler that temporarily sets the dbauthz context
@@ -35,3 +36,16 @@ func AsAuthzSystem(mws ...func(http.Handler) http.Handler) func(http.Handler) ht
3536
})
3637
}
3738
}
39+
40+
// AttachAuthzCache enables the authz cache for the authorizer. All rbac checks will
41+
// run against the cache, meaning duplicate checks will not be performed.
42+
//
43+
// Note the cache is safe for multiple actors. So mixing user and system checks
44+
// is ok.
45+
funcAttachAuthzCache(next http.Handler) http.Handler {
46+
returnhttp.HandlerFunc(func(rw http.ResponseWriter,r*http.Request) {
47+
ctx:=rbac.WithCacheCtx(r.Context())
48+
49+
next.ServeHTTP(rw,r.WithContext(ctx))
50+
})
51+
}

‎coderd/rbac/authz.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ var (
158158
partialQuery rego.PreparedPartialQuery
159159
)
160160

161+
// NewCachingAuthorizer returns a new RegoAuthorizer that supports context based
162+
// caching. To utilize the caching, the context passed to Authorize() must be
163+
// created with 'WithCacheCtx(ctx)'.
164+
funcNewCachingAuthorizer(registry prometheus.Registerer)Authorizer {
165+
returnCacher(NewAuthorizer(registry))
166+
}
167+
161168
funcNewAuthorizer(registry prometheus.Registerer)*RegoAuthorizer {
162169
queryOnce.Do(func() {
163170
varerrerror

‎coderd/rbac/authz_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func BenchmarkRBACAuthorize(b *testing.B) {
109109
uuid.MustParse("0632b012-49e0-4d70-a5b3-f4398f1dcd52"),
110110
uuid.MustParse("70dbaa7a-ea9c-4f68-a781-97b08af8461d"),
111111
)
112-
authorizer:=rbac.NewAuthorizer(prometheus.NewRegistry())
112+
authorizer:=rbac.NewCachingAuthorizer(prometheus.NewRegistry())
113113
// This benchmarks all the simple cases using just user permissions. Groups
114114
// are added as noise, but do not do anything.
115115
for_,c:=rangebenchCases {
@@ -136,7 +136,7 @@ func BenchmarkRBACAuthorizeGroups(b *testing.B) {
136136
uuid.MustParse("0632b012-49e0-4d70-a5b3-f4398f1dcd52"),
137137
uuid.MustParse("70dbaa7a-ea9c-4f68-a781-97b08af8461d"),
138138
)
139-
authorizer:=rbac.NewAuthorizer(prometheus.NewRegistry())
139+
authorizer:=rbac.NewCachingAuthorizer(prometheus.NewRegistry())
140140

141141
// Same benchmark cases, but this time groups will be used to match.
142142
// Some '*' permissions will still match, but using a fake action reduces
@@ -188,7 +188,7 @@ func BenchmarkRBACFilter(b *testing.B) {
188188
uuid.MustParse("70dbaa7a-ea9c-4f68-a781-97b08af8461d"),
189189
)
190190

191-
authorizer:=rbac.NewAuthorizer(prometheus.NewRegistry())
191+
authorizer:=rbac.NewCachingAuthorizer(prometheus.NewRegistry())
192192

193193
for_,c:=rangebenchCases {
194194
b.Run("PrepareOnly-"+c.Name,func(b*testing.B) {

‎coderd/rbac/builtin_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type authSubject struct {
2323
funcTestRolePermissions(t*testing.T) {
2424
t.Parallel()
2525

26-
auth:=rbac.NewAuthorizer(prometheus.NewRegistry())
26+
auth:=rbac.NewCachingAuthorizer(prometheus.NewRegistry())
2727

2828
// currentUser is anything that references "me", "mine", or "my".
2929
currentUser:=uuid.New()

‎coderd/rbac/cache.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type cachedCalls struct {
2020
// multiple calls are made to the Authorizer for the same subject, action, and
2121
// object. The cache is on each `ctx` and is not shared between requests.
2222
// If no cache is found on the context, the Authorizer is called as normal.
23+
//
24+
// Cacher is safe for multiple actors.
2325
funcCacher(authzAuthorizer)Authorizer {
2426
return&cachedCalls{authz:authz}
2527
}

‎coderd/rbac/cache_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package rbac_test
22

33
import (
44
"context"
5+
"fmt"
56
"testing"
67

78
"github.com/stretchr/testify/require"
@@ -10,6 +11,33 @@ import (
1011
"github.com/coder/coder/coderd/rbac"
1112
)
1213

14+
// BenchmarkCacher benchmarks the performance of the cacher with a given
15+
// cache size. The expected cache size in prod will usually be 1-2. In Filter
16+
// cases it can get as high as 10.
17+
funcBenchmarkCacher(b*testing.B) {
18+
b.ResetTimer()
19+
// Size of the cache.
20+
sizes:= []int{1,10,100,1000}
21+
for_,size:=rangesizes {
22+
b.Run(fmt.Sprintf("Size%d",size),func(b*testing.B) {
23+
ctx:=rbac.WithCacheCtx(context.Background())
24+
authz:=rbac.Cacher(&coderdtest.FakeAuthorizer{AlwaysReturn:nil})
25+
fori:=0;i<size;i++ {
26+
// Preload the cache of a given size
27+
subj,obj,action:=coderdtest.RandomRBACSubject(),coderdtest.RandomRBACObject(),coderdtest.RandomRBACAction()
28+
_=authz.Authorize(ctx,subj,action,obj)
29+
}
30+
31+
// Cache is loaded as a slice, so this cache hit is always the last element.
32+
subj,obj,action:=coderdtest.RandomRBACSubject(),coderdtest.RandomRBACObject(),coderdtest.RandomRBACAction()
33+
b.ResetTimer()
34+
fori:=0;i<b.N;i++ {
35+
_=authz.Authorize(ctx,subj,action,obj)
36+
}
37+
})
38+
}
39+
}
40+
1341
funcTestCacher(t*testing.T) {
1442
t.Parallel()
1543

‎enterprise/coderd/coderd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func New(ctx context.Context, options *Options) (*API, error) {
4747
options.PrometheusRegistry=prometheus.NewRegistry()
4848
}
4949
ifoptions.Options.Authorizer==nil {
50-
options.Options.Authorizer=rbac.NewAuthorizer(options.PrometheusRegistry)
50+
options.Options.Authorizer=rbac.NewCachingAuthorizer(options.PrometheusRegistry)
5151
}
5252
ctx,cancelFunc:=context.WithCancel(ctx)
5353
api:=&API{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp