@@ -9,13 +9,14 @@ import (
99
1010 "github.com/flanksource/commons/collections"
1111 "github.com/flanksource/commons/logger"
12+ dutyAPI "github.com/flanksource/duty/api"
1213 "github.com/flanksource/duty/context"
1314 "github.com/flanksource/duty/models"
1415 dutyRBAC "github.com/flanksource/duty/rbac"
1516 "github.com/flanksource/duty/rbac/policy"
1617 "github.com/flanksource/duty/rls"
17- "github.com/flanksource/duty/types"
1818 "github.com/google/uuid"
19+ "github.com/lib/pq"
1920 "github.com/samber/lo"
2021 "go.opentelemetry.io/otel/trace"
2122 "gorm.io/gorm"
@@ -75,11 +76,26 @@ func WithRLS(ctx context.Context, fn func(context.Context) error) error {
7576 }
7677
7778 if rlsPayload .Disable {
78- return fn (ctx )
79+ return ctx .Transaction (func (txCtx context.Context , _ trace.Span ) error {
80+ role := dutyAPI .DefaultConfig .Postgrest .DBRoleBypass
81+ if role == "" {
82+ role = dutyAPI .DefaultConfig .Postgrest .DBRole
83+ if role != "" {
84+ txCtx .Logger .Warnf ("RLS bypass role not configured, using role=%s" , role )
85+ }
86+ }
87+ if role == "" {
88+ return fmt .Errorf ("role is required" )
89+ }
90+ if err := txCtx .DB ().Exec (fmt .Sprintf ("SET LOCAL ROLE %s" , pq .QuoteIdentifier (role ))).Error ; err != nil {
91+ return err
92+ }
93+ return fn (txCtx )
94+ })
7995 }
8096
8197 return ctx .Transaction (func (txCtx context.Context , _ trace.Span ) error {
82- if err := rlsPayload .SetPostgresSessionRLS (txCtx .DB ()); err != nil {
98+ if err := rlsPayload .SetPostgresSessionRLSWithRole (txCtx .DB (), dutyAPI . DefaultConfig . Postgrest . DBRole ); err != nil {
8399 return err
84100 }
85101
@@ -110,7 +126,6 @@ func buildRLSPayloadFromScopes(ctx context.Context) (*rls.Payload, error) {
110126 }
111127
112128 scopeIDs := map [uuid.UUID ]struct {}{}
113- wildcards := map [rls.WildcardResourceScope ]struct {}{}
114129
115130 for _ , perm := range permissions {
116131 if ! collections .MatchItems (policy .ActionRead , strings .Split (perm .Action , "," )... ) {
@@ -123,19 +138,6 @@ func buildRLSPayloadFromScopes(ctx context.Context) (*rls.Payload, error) {
123138 scopeIDs [permScopeID ] = struct {}{}
124139 }
125140
126- switch perm .Object {
127- case policy .ObjectCatalog :
128- wildcards [rls .WildcardResourceScopeConfig ] = struct {}{}
129- case policy .ObjectTopology :
130- wildcards [rls .WildcardResourceScopeComponent ] = struct {}{}
131- case policy .ObjectCanary :
132- wildcards [rls .WildcardResourceScopeCanary ] = struct {}{}
133- case policy .ObjectPlaybooks :
134- wildcards [rls .WildcardResourceScopePlaybook ] = struct {}{}
135- case policy .ObjectViews :
136- wildcards [rls .WildcardResourceScopeView ] = struct {}{}
137- }
138-
139141 if len (perm .ObjectSelector ) == 0 {
140142 continue
141143 }
@@ -148,42 +150,26 @@ func buildRLSPayloadFromScopes(ctx context.Context) (*rls.Payload, error) {
148150
149151 // Process scope references (indirect permissions)
150152 if len (selectors .Scopes ) > 0 {
151- if err := processScopeRefs (ctx , selectors .Scopes , scopeIDs , wildcards ); err != nil {
153+ if err := processScopeRefs (ctx , selectors .Scopes , scopeIDs ); err != nil {
152154 return nil , err
153155 }
154156 }
155157
156158 // Process direct resource selectors (configs, components, playbooks, etc.)
157159 if len (selectors .Configs ) > 0 {
158- if hasWildcardSelector (selectors .Configs ) {
159- wildcards [rls .WildcardResourceScopeConfig ] = struct {}{}
160- } else {
161- scopeIDs [permScopeID ] = struct {}{}
162- }
160+ scopeIDs [permScopeID ] = struct {}{}
163161 }
164162
165163 if len (selectors .Components ) > 0 {
166- if hasWildcardSelector (selectors .Components ) {
167- wildcards [rls .WildcardResourceScopeComponent ] = struct {}{}
168- } else {
169- scopeIDs [permScopeID ] = struct {}{}
170- }
164+ scopeIDs [permScopeID ] = struct {}{}
171165 }
172166
173167 if len (selectors .Playbooks ) > 0 {
174- if hasWildcardSelector (selectors .Playbooks ) {
175- wildcards [rls .WildcardResourceScopePlaybook ] = struct {}{}
176- } else {
177- scopeIDs [permScopeID ] = struct {}{}
178- }
168+ scopeIDs [permScopeID ] = struct {}{}
179169 }
180170
181171 if len (selectors .Views ) > 0 {
182- if hasWildcardViewRef (selectors .Views ) {
183- wildcards [rls .WildcardResourceScopeView ] = struct {}{}
184- } else {
185- scopeIDs [permScopeID ] = struct {}{}
186- }
172+ scopeIDs [permScopeID ] = struct {}{}
187173 }
188174
189175 // TODO: No RLS support for connections yet!
@@ -195,15 +181,14 @@ func buildRLSPayloadFromScopes(ctx context.Context) (*rls.Payload, error) {
195181 }
196182
197183 payload := & rls.Payload {
198- Scopes : setToSortedUUIDSlice (scopeIDs ),
199- WildcardScopes : setToSortedWildcardSlice (wildcards ),
184+ Scopes : setToSortedUUIDSlice (scopeIDs ),
200185 }
201186
202187 return payload , nil
203188}
204189
205- // processScopeRefs fetches scopes from database and adds their IDs and wildcard types
206- func processScopeRefs (ctx context.Context , scopeRefs []dutyRBAC.NamespacedNameIDSelector , scopeIDs map [uuid.UUID ]struct {}, wildcards map [rls. WildcardResourceScope ] struct {} ) error {
190+ // processScopeRefs fetches scopes from database and adds their IDs
191+ func processScopeRefs (ctx context.Context , scopeRefs []dutyRBAC.NamespacedNameIDSelector , scopeIDs map [uuid.UUID ]struct {}) error {
207192 for _ , ref := range scopeRefs {
208193 var scope models.Scope
209194 err := ctx .DB ().
@@ -220,78 +205,11 @@ func processScopeRefs(ctx context.Context, scopeRefs []dutyRBAC.NamespacedNameID
220205 // Always include scope UUID for view row-level grants
221206 scopeIDs [scope .ID ] = struct {}{}
222207
223- var targets []v1.ScopeTarget
224- if err := json .Unmarshal ([]byte (scope .Targets ), & targets ); err != nil {
225- ctx .Warnf ("failed to unmarshal targets for scope %s: %v" , scope .ID , err )
226- continue
227- }
228-
229- for _ , target := range targets {
230- switch {
231- case target .Config != nil :
232- if isWildcardScopeSelector (target .Config ) {
233- wildcards [rls .WildcardResourceScopeConfig ] = struct {}{}
234- }
235- case target .Component != nil :
236- if isWildcardScopeSelector (target .Component ) {
237- wildcards [rls .WildcardResourceScopeComponent ] = struct {}{}
238- }
239- case target .Playbook != nil :
240- if isWildcardScopeSelector (target .Playbook ) {
241- wildcards [rls .WildcardResourceScopePlaybook ] = struct {}{}
242- }
243- case target .Canary != nil :
244- if isWildcardScopeSelector (target .Canary ) {
245- wildcards [rls .WildcardResourceScopeCanary ] = struct {}{}
246- }
247- case target .View != nil :
248- if isWildcardScopeSelector (target .View ) {
249- wildcards [rls .WildcardResourceScopeView ] = struct {}{}
250- }
251- case target .Global != nil :
252- if isWildcardScopeSelector (target .Global ) {
253- wildcards [rls .WildcardResourceScopeConfig ] = struct {}{}
254- wildcards [rls .WildcardResourceScopeComponent ] = struct {}{}
255- wildcards [rls .WildcardResourceScopePlaybook ] = struct {}{}
256- wildcards [rls .WildcardResourceScopeCanary ] = struct {}{}
257- wildcards [rls .WildcardResourceScopeView ] = struct {}{}
258- }
259- }
260- }
261208 }
262209
263210 return nil
264211}
265212
266- func isWildcardScopeSelector (selector * v1.ScopeResourceSelector ) bool {
267- if selector == nil {
268- return false
269- }
270-
271- return selector .Name == "*" &&
272- selector .Namespace == "" &&
273- selector .Agent == "" &&
274- selector .TagSelector == ""
275- }
276-
277- func hasWildcardSelector (selectors []types.ResourceSelector ) bool {
278- for _ , selector := range selectors {
279- if selector .Wildcard () {
280- return true
281- }
282- }
283- return false
284- }
285-
286- func hasWildcardViewRef (selectors []dutyRBAC.ViewRef ) bool {
287- for _ , selector := range selectors {
288- if selector .Name == "*" && selector .Namespace == "" && selector .ID == "" {
289- return true
290- }
291- }
292- return false
293- }
294-
295213func setToSortedUUIDSlice (set map [uuid.UUID ]struct {}) []uuid.UUID {
296214 if len (set ) == 0 {
297215 return nil
@@ -308,20 +226,3 @@ func setToSortedUUIDSlice(set map[uuid.UUID]struct{}) []uuid.UUID {
308226
309227 return out
310228}
311-
312- func setToSortedWildcardSlice (set map [rls.WildcardResourceScope ]struct {}) []rls.WildcardResourceScope {
313- if len (set ) == 0 {
314- return nil
315- }
316-
317- out := make ([]rls.WildcardResourceScope , 0 , len (set ))
318- for val := range set {
319- out = append (out , val )
320- }
321-
322- sort .Slice (out , func (i , j int ) bool {
323- return string (out [i ]) < string (out [j ])
324- })
325-
326- return out
327- }
0 commit comments